diff --git a/.bazelrc b/.bazelrc index 273b36af5..91fb6415e 100644 --- a/.bazelrc +++ b/.bazelrc @@ -12,8 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Use blake3 as digest function instead of the much slower default sha256. -startup --digest_function=blake3 +# Keep Bazel aligned with NativeLink's default digest function. +startup --digest_function=sha256 common --enable_platform_specific_config # Don't use legacy toolchain resolution. @@ -96,7 +96,6 @@ build --@rules_rust//:extra_rustc_flag=-Wmissing_debug_implementations build --@rules_rust//:extra_rustc_flag=-Wnoop_method_call build --@rules_rust//:extra_rustc_flag=-Dopaque_hidden_inferred_bound build --@rules_rust//:extra_rustc_flag=-Doverlapping_range_endpoints -build --@rules_rust//:extra_rustc_flag=-Wsingle_use_lifetimes build --@rules_rust//:extra_rustc_flag=-Dsuspicious_double_ref_op build --@rules_rust//:extra_rustc_flag=-Wtrivial_casts build --@rules_rust//:extra_rustc_flag=-Wtrivial_numeric_casts @@ -113,16 +112,15 @@ build --@rules_rust//:extra_rustc_flag=-Wunused_lifetimes build --@rules_rust//:extra_rustc_flag=-Wunused_qualifications build --@rules_rust//:extra_rustc_flag=-Wvariant_size_differences -build --@rules_rust//:clippy_flag=-Wclippy::all -build --@rules_rust//:clippy_flag=-Wclippy::nursery -build --@rules_rust//:clippy_flag=-Wclippy::pedantic +build --@rules_rust//:clippy_flag=-Dclippy::all +build --@rules_rust//:clippy_flag=-Dclippy::nursery +build --@rules_rust//:clippy_flag=-Dclippy::pedantic build --@rules_rust//:clippy_flag=-Dclippy::alloc_instead_of_core build --@rules_rust//:clippy_flag=-Dclippy::as_underscore build --@rules_rust//:clippy_flag=-Dclippy::await_holding_lock build --@rules_rust//:clippy_flag=-Dclippy::bind_instead_of_map build --@rules_rust//:clippy_flag=-Dclippy::collapsible_if build --@rules_rust//:clippy_flag=-Wclippy::dbg_macro -build --@rules_rust//:clippy_flag=-Wclippy::decimal_literal_representation build --@rules_rust//:clippy_flag=-Dclippy::disallowed_methods build --@rules_rust//:clippy_flag=-Dclippy::doc_markdown build --@rules_rust//:clippy_flag=-Dclippy::elidable_lifetime_names @@ -160,7 +158,7 @@ build --@rules_rust//:clippy_flag=-Dclippy::use_debug build --@rules_rust//:clippy_flag=-Dclippy::used_underscore_binding build --@rules_rust//:clippy_flag=-Dclippy::useless_format build --@rules_rust//:clippy_flag=-Dclippy::cast_possible_truncation -build --@rules_rust//:clippy_flag=-Aclippy::cast_possible_wrap +build --@rules_rust//:clippy_flag=-Dclippy::cast_possible_wrap build --@rules_rust//:clippy_flag=-Aclippy::cast_precision_loss build --@rules_rust//:clippy_flag=-Aclippy::cast_sign_loss build --@rules_rust//:clippy_flag=-Aclippy::cognitive_complexity @@ -234,5 +232,8 @@ try-import %workspace%/nixos.bazelrc # Generated by the nativelink flake module. try-import %workspace%/nativelink.bazelrc +# Opt-in NativeLink Cloud configs used by this repo's CI. +try-import %workspace%/ci.bazelrc + # Allow user-side customization. try-import %workspace%/user.bazelrc diff --git a/.bazelversion b/.bazelversion index 3beeadd42..44931da26 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -9.0.2 +9.1.1 diff --git a/.claude/skills/migrate-to-bazelmod/SKILL.md b/.claude/skills/migrate-to-bazelmod/SKILL.md index be40a6673..4d5cf8847 100644 --- a/.claude/skills/migrate-to-bazelmod/SKILL.md +++ b/.claude/skills/migrate-to-bazelmod/SKILL.md @@ -711,4 +711,4 @@ If a migration step in this skill doesn't fit the project (unusual repository la - Email: support@nativelink.com - Cloud: https://app.nativelink.com (zero-config remote cache plus remote execution) -NativeLink ships build cache and remote execution for Bazel/Buck2/Goma/Reclient at over a billion requests per month, and the team handles Bazel-modules migrations as part of normal customer support. +NativeLink ships build cache and remote execution for Bazel/Buck2/Goma/Siso at over a billion requests per month, and the team handles Bazel-modules migrations as part of normal customer support. diff --git a/.dockerignore b/.dockerignore index df99d5c3f..34f731f19 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,3 +6,4 @@ target/ .git deployment-examples bazel-* +user.bazelrc diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..d5ed0966a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,120 @@ +name: Bug Report +description: File a bug report to help us improve NativeLink +title: "[Bug]: " +labels: ["type:bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! Need help right away? + Join our [Slack community](https://forms.gle/LtaWSixEC6bYi5xF7) for faster responses. + + - type: input + id: version + attributes: + label: Version + description: What version of NativeLink are you running? + placeholder: "e.g. v1.0.0, main@abc1234, or ghcr.io image tag" + validations: + required: true + + - type: dropdown + id: client + attributes: + label: Client + description: Which client are you using with NativeLink? + options: + - Bazel + - Buck2 + - Other + validations: + required: true + + - type: input + id: os_arch + attributes: + label: OS / Architecture + description: What operating system and architecture? + placeholder: "e.g. Linux x86_64, macOS arm64" + validations: + required: true + + - type: dropdown + id: deployment + attributes: + label: Deployment method + description: How are you deploying NativeLink? + options: + - Docker + - Nix + - Kubernetes + - Bare metal + - Other + validations: + required: true + + - type: dropdown + id: storage + attributes: + label: Storage backend + description: Which storage backend are you using for the CAS? + options: + - S3 + - GCS + - Azure Blob + - Local filesystem + - Redis + - Other + validations: + required: true + + - type: input + id: workers + attributes: + label: Number of workers + description: How many workers are in your deployment? (if applicable) + placeholder: "e.g. 10" + + - type: input + id: cas_size + attributes: + label: Rough size of CAS + description: Approximately how large is your CAS store? + placeholder: "e.g. ~50GiB on local SSD" + + - type: textarea + id: config + attributes: + label: Configuration + description: Please paste a sanitized version of your NativeLink configuration. + render: json5 + placeholder: "{\n ...\n}" + + - type: textarea + id: expected_behavior + attributes: + label: Expected behavior + description: What did you expect to happen? + validations: + required: true + + - type: textarea + id: actual_behavior + attributes: + label: Actual behavior + description: What actually happened? + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Logs / error output + description: Please paste any relevant logs, error messages, or stack traces. + render: shell + + - type: textarea + id: context + attributes: + label: Additional context + description: Anything else you think would be useful (links, references, screenshots, etc.). diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..1aedb2bc4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Join our Slack community + url: https://forms.gle/LtaWSixEC6bYi5xF7 + about: Get faster responses from the NativeLink community + - name: Commercial support + url: mailto:marcus@tracemachina.com + about: Contact us for commercial support inquiries diff --git a/.github/ISSUE_TEMPLATE/config_help.yml b/.github/ISSUE_TEMPLATE/config_help.yml new file mode 100644 index 000000000..773df8f98 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config_help.yml @@ -0,0 +1,108 @@ +name: Configuration / Deployment Help +description: Ask for help with configuring, deploying, or troubleshooting NativeLink +title: "[Config/Help]: " +labels: ["type:question"] +body: + - type: markdown + attributes: + value: | + We're here to help! For faster responses, consider joining our + [Slack community](https://forms.gle/LtaWSixEC6bYi5xF7). For commercial + support, email us at contact@nativelink.com. + + - type: input + id: version + attributes: + label: Version + description: What version of NativeLink are you running? + placeholder: "e.g. v1.0.0, main@abc1234, or ghcr.io image tag" + validations: + required: true + + - type: dropdown + id: client + attributes: + label: Client + description: Which client are you using with NativeLink? + options: + - Bazel + - Buck2 + - Other + validations: + required: true + + - type: input + id: os_arch + attributes: + label: OS / Architecture + description: What operating system and architecture? + placeholder: "e.g. Linux x86_64, macOS arm64" + validations: + required: true + + - type: dropdown + id: deployment + attributes: + label: Deployment method + description: How are you deploying NativeLink? + options: + - Docker + - Nix + - Kubernetes + - Bare metal + - Other + validations: + required: true + + - type: dropdown + id: storage + attributes: + label: Storage backend + description: Which storage backend are you using for the CAS? + options: + - S3 + - GCS + - Azure Blob + - Local filesystem + - Redis + - Other + validations: + required: true + + - type: input + id: workers + attributes: + label: Number of workers + description: How many workers are in your deployment? (if applicable) + placeholder: "e.g. 10" + + - type: input + id: cas_size + attributes: + label: Rough size of CAS + description: Approximately how large is your CAS store? + placeholder: "e.g. ~50GiB on local SSD" + + - type: textarea + id: config + attributes: + label: Configuration + description: Please paste a sanitized version of your NativeLink configuration. + render: json5 + placeholder: "{\n ...\n}" + + - type: textarea + id: question + attributes: + label: What do you need help with? + description: Describe your question or issue in detail. + placeholder: "I'm trying to configure..." + validations: + required: true + + - type: textarea + id: tried + attributes: + label: What have you tried so far? + description: Steps you've already taken to resolve this. + placeholder: "I've tried..." diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..4ab2a0edc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,40 @@ +name: Feature Request +description: Suggest an idea or improvement for NativeLink +title: "[Feature]: " +labels: ["type:enhancement"] +body: + - type: markdown + attributes: + value: | + Thanks for sharing your idea! Need to discuss it first? + Join our [Slack community](https://forms.gle/LtaWSixEC6bYi5xF7) for faster feedback. + + - type: textarea + id: problem + attributes: + label: Problem statement + description: What problem are you trying to solve? What use case does this unlock? + placeholder: "I'm always frustrated when..." + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: What would you like to see added or changed? + placeholder: "A new configuration option that..." + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: What workarounds or alternative solutions have you considered? + + - type: textarea + id: context + attributes: + label: Additional context + description: Any links, references, screenshots, or prior art that informed this request. diff --git a/.github/ISSUE_TEMPLATE/general.yml b/.github/ISSUE_TEMPLATE/general.yml new file mode 100644 index 000000000..e8a3b7086 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/general.yml @@ -0,0 +1,44 @@ +name: General Issue +description: For anything that doesn't fit the other categories +title: "[General]: " +labels: ["needs:triage"] +body: + - type: markdown + attributes: + value: | + Not sure if this is a bug or feature? Feel free to use this template. + For real-time help, join our [Slack community](https://forms.gle/LtaWSixEC6bYi5xF7). + + - type: dropdown + id: type + attributes: + label: Issue type + options: + - Question + - Discussion + - Suggestion + - Other + validations: + required: true + + - type: input + id: version + attributes: + label: Version (if applicable) + description: What version of NativeLink are you running? + placeholder: "e.g. v1.0.0, main@abc1234" + + - type: textarea + id: description + attributes: + label: Description + description: What's on your mind? + placeholder: "Tell us what you're thinking about..." + validations: + required: true + + - type: textarea + id: context + attributes: + label: Additional context + description: Any links, references, or screenshots that help explain. diff --git a/.github/actions/free-disk/action.yaml b/.github/actions/free-disk/action.yaml index 2bf00b955..77e405e4b 100644 --- a/.github/actions/free-disk/action.yaml +++ b/.github/actions/free-disk/action.yaml @@ -13,18 +13,26 @@ runs: endersonmenezes/free-disk-space@7901478139cff6e9d44df5972fd8ab8fcade4db1 with: rm_cmd: "rmz" # For speed up + rmz_version: "3.2.0" remove_android: false # Takes too long. remove_dotnet: true remove_haskell: true - remove_tool_cache: false # TODO(palfrey): Do we really need this? - # Note: Not deleting google-cloud-cli because it takes too long. + remove_tool_cache: false remove_folders: > + /opt/go + /opt/Ruby + /opt/microsoft/msedge + /usr/local/lib/android /usr/share/swift /usr/share/miniconda /usr/share/az* /usr/share/glade* /usr/local/share/chromium /usr/local/share/powershell + /usr/local/julia + /usr/local/aws-cli + /usr/local/aws-sam-cli + /usr/share/gradle # using hints from https://github.com/actions/runner-images/issues/10511#issuecomment-3984466720 - if: runner.os == 'macOS' diff --git a/.github/actions/prepare-nix/action.yaml b/.github/actions/prepare-nix/action.yaml index 8c0532852..af22f0a35 100644 --- a/.github/actions/prepare-nix/action.yaml +++ b/.github/actions/prepare-nix/action.yaml @@ -11,10 +11,17 @@ runs: uses: ./.github/actions/free-disk - name: Install Nix + # Stay on the Determinate installer: the nix-quick-install switch (Nix + # 2.34.7) makes the nix2container multi-arch image publish fail with a + # layer digest mismatch. See the tagged image workflow. uses: >- # https://github.com/DeterminateSystems/nix-installer-action/releases/tag/v22 DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 with: source-tag: v3.13.0 + extra-conf: | + fallback = true # So we always work even if the cache is down + log-lines = 100 # Necessary in CI to get enough failure context + keep-outputs = true # Don't delete non-root outputs, because might be needed for other builds - name: Setup attic cache uses: >- # v4 @@ -22,8 +29,10 @@ runs: with: timeout_minutes: 30 max_attempts: 3 + retry_wait_seconds: 30 # if we're failing, we want to wait a reasonable amount of time command: | set -euo pipefail + date cd /tmp nix build nixpkgs#attic-client # Note NATIVELINK_ATTIC_TOKEN is blank for PR builds as they don't have secret access @@ -37,7 +46,7 @@ runs: # * https://github.com/zhaofengli/attic/issues/226 # * https://github.com/zhaofengli/attic/pull/317 # We use the original one first to get caching of this - nix build --fallback github:TraceMachina/attic + nix build github:TraceMachina/attic RUST_BACKTRACE=full RUST_LOG=debug,hyper_util=info,rustls=info ./result/bin/attic watch-store nativelink &> attic-push.log & # For the cases where we don't have a cache of it, push it diff --git a/.github/actions/setup-nativelink-cloud/action.yaml b/.github/actions/setup-nativelink-cloud/action.yaml new file mode 100644 index 000000000..5165e4dd3 --- /dev/null +++ b/.github/actions/setup-nativelink-cloud/action.yaml @@ -0,0 +1,207 @@ +--- +name: Setup NativeLink Cloud +description: >- + Writes a user.bazelrc that opts this job into NativeLink Cloud remote + cache/BES (and optionally remote execution) via the configs in ci.bazelrc. + Trusted lanes pass secret-fed credentials; fork PRs, which receive neither + secrets nor repository variables, fall back to the committed public + read-only defaults below (cache reads only — no uploads, no BES, no remote + execution). ci-mode 'off' disables trusted lanes; the public path's kill + switch is revoking the public key server-side. + +inputs: + api-key: + description: >- + NativeLink Cloud API key. Empty (fork PRs have no secrets) disables the + setup entirely. + required: false + default: '' + claim-base: + description: >- + Claim endpoint base as ., normally passed from + secrets.NATIVELINK_STAGING_CLAIM_BASE. The action derives the + grpcs://cas-, bes-, and scheduler- endpoints from it. Empty disables + the setup. + required: false + default: '' + bes-results-url: + description: >- + Optional console URL prefix for invocation links, normally passed from + secrets.NATIVELINK_STAGING_BES_RESULTS_URL. Omitted from the build when + empty. + required: false + default: '' + public-read-key: + description: >- + World-readable cache_read-only API key used when api-key/claim-base are + unavailable (fork PRs receive neither secrets nor repository variables, + so the value must live here as a committed default to reach them). + Deliberately public: fork code runs with the value in hand either way, + so it must never carry more than cache_read. Kill switch is revoking + the key server-side; rotation is editing this default. + required: false + default: '66532088547d98bfb5b0b41e8d5cbfea8b5da1bc1e23e776f9cefc12654c6cb6' + public-claim-base: + description: >- + Claim endpoint base for the public read-only path. Committed default + for the same reason as public-read-key. + required: false + default: 'marcus-eagan-h6a62e.staging.scdev.nativelink.net' + ci-mode: + description: >- + Kill switch, normally passed as vars.NATIVELINK_CI_MODE. Empty or 'off' + disables; 'cache' enables remote cache + BES; 'rbe' additionally honors + exec: on. The canary workflow pins this to 'cache'/'rbe' so it stays + live while regular lanes are dark. + required: false + default: '' + mode: + description: >- + 'read' (PR lanes; never uploads action results) or 'write' (main-branch + push lanes; only TraceMachina main-branch identities hold write keys). + required: false + default: read + exec: + description: >- + 'on' requests remote execution. Honored only when ci-mode is 'rbe', and + only on Linux runners. + required: false + default: 'off' + container-image: + description: >- + Exec property attached when remote execution is honored. Must + byte-for-byte match the container-image the claim's worker pool + advertises, or actions queue forever. + required: false + default: debian:bookworm-slim + +outputs: + enabled: + description: "'true' when a user.bazelrc was written, else 'false'." + value: ${{ steps.configure.outputs.enabled }} + +runs: + using: composite + steps: + - name: Write user.bazelrc + id: configure + shell: bash + env: + NL_API_KEY: ${{ inputs.api-key }} + NL_CLAIM_BASE: ${{ inputs.claim-base }} + NL_BES_RESULTS_URL: ${{ inputs.bes-results-url }} + NL_PUBLIC_KEY: ${{ inputs.public-read-key }} + NL_PUBLIC_CLAIM_BASE: ${{ inputs.public-claim-base }} + NL_CI_MODE: ${{ inputs.ci-mode }} + NL_MODE: ${{ inputs.mode }} + NL_EXEC: ${{ inputs.exec }} + NL_CONTAINER_IMAGE: ${{ inputs.container-image }} + run: | + set -euo pipefail + + # Start from a deterministic file. In addition to preventing duplicate + # options if this action is invoked twice, an empty file lets Docker + # builds mount it as an optional BuildKit secret when cloud CI is off. + : > user.bazelrc + + write_ci_metadata() { + { + echo "common --build_metadata=ROLE=CI" + echo "common --build_metadata=GITHUB_REPOSITORY=${GITHUB_REPOSITORY:-unknown}" + echo "common --build_metadata=GITHUB_SHA=${GITHUB_SHA:-unknown}" + echo "common --build_metadata=GITHUB_RUN_ID=${GITHUB_RUN_ID:-unknown}" + echo "common --build_metadata=GITHUB_RUN_NUMBER=${GITHUB_RUN_NUMBER:-unknown}" + echo "common --build_metadata=GITHUB_RUN_ATTEMPT=${GITHUB_RUN_ATTEMPT:-unknown}" + echo "common --build_metadata=GITHUB_JOB=${GITHUB_JOB:-unknown}" + echo "common --build_metadata=GITHUB_EVENT_NAME=${GITHUB_EVENT_NAME:-unknown}" + echo "common --build_metadata=GITHUB_REF=${GITHUB_REF:-unknown}" + echo "common --build_metadata=RUNNER_OS=${RUNNER_OS:-unknown}" + echo "common --build_metadata=RUNNER_ARCH=${RUNNER_ARCH:-unknown}" + echo "common --bes_keywords=role=CI,repository=${GITHUB_REPOSITORY:-unknown},job=${GITHUB_JOB:-unknown},event=${GITHUB_EVENT_NAME:-unknown}" + } >> user.bazelrc + } + + cred_kind="" + if [[ "$NL_CI_MODE" != "off" ]]; then + if [[ -n "$NL_API_KEY" && -n "$NL_CLAIM_BASE" ]]; then + # Private credentials also require the kill-switch variable to be + # explicitly on; never silently downgrade a trusted lane to the + # public path. + if [[ -n "$NL_CI_MODE" ]]; then + cred_kind="private" + fi + elif [[ -n "$NL_PUBLIC_KEY" && -n "$NL_PUBLIC_CLAIM_BASE" ]]; then + # Fork runs receive neither secrets nor repository variables, so + # the public read-only path cannot depend on ci-mode; revoking + # the public key server-side is its kill switch. + cred_kind="public" + fi + fi + + if [[ -z "$cred_kind" ]]; then + write_ci_metadata + echo "enabled=false" >> "$GITHUB_OUTPUT" + echo "NativeLink Cloud disabled (no credentials or ci-mode off); building locally." + exit 0 + fi + + exec_enabled=false + if [[ "$NL_EXEC" == "on" ]]; then + if [[ "$RUNNER_OS" != "Linux" ]]; then + # macOS auto-applies LRE platforms from lre.bazelrc that conflict + # with the nl-rbe Linux platform, and no non-Linux workers exist. + echo "exec: on is only supported on Linux runners (got $RUNNER_OS)" >&2 + exit 1 + fi + # Remote execution needs a write-capable identity; the public + # read-only path never executes remotely. + if [[ "$NL_CI_MODE" == "rbe" && "$cred_kind" == "private" ]]; then + exec_enabled=true + fi + fi + + if [[ "$cred_kind" == "public" ]]; then + { + echo "common --config=nl-cache" + echo "common --remote_cache=grpcs://cas-${NL_PUBLIC_CLAIM_BASE}" + # The public key carries cache_read only: no uploads, no BES. + echo "common --remote_upload_local_results=false" + echo "common --remote_header=x-nativelink-api-key=${NL_PUBLIC_KEY}" + echo "common --remote_header=x-nativelink-project=nativelink-github-ci" + } >> user.bazelrc + write_ci_metadata + echo "enabled=true" >> "$GITHUB_OUTPUT" + echo "NativeLink Cloud enabled: public read-only cache (no uploads, no BES)" + exit 0 + fi + + { + echo "common --config=nl-cache" + echo "common --remote_cache=grpcs://cas-${NL_CLAIM_BASE}" + echo "common --bes_backend=grpcs://bes-${NL_CLAIM_BASE}" + if [[ -n "$NL_BES_RESULTS_URL" ]]; then + echo "common --bes_results_url=${NL_BES_RESULTS_URL}" + fi + if [[ "$exec_enabled" == true ]]; then + echo "common --remote_executor=grpcs://scheduler-${NL_CLAIM_BASE}:443" + echo "common --remote_default_exec_properties=container-image=${NL_CONTAINER_IMAGE}" + echo "common --config=nl-rbe" + fi + if [[ "$NL_MODE" == "write" ]]; then + echo "common --config=nl-write" + else + # Plain (non-config) line so it also beats the nix-generated + # nativelink.bazelrc on lanes that run under nix develop. + echo "common --remote_upload_local_results=false" + fi + # Both headers from the same variable: a truncated BES key once + # caused silent 401s while the cache header kept working. + echo "common --remote_header=x-nativelink-api-key=${NL_API_KEY}" + echo "common --bes_header=x-nativelink-api-key=${NL_API_KEY}" + echo "common --remote_header=x-nativelink-project=nativelink-github-ci" + } >> user.bazelrc + write_ci_metadata + + echo "enabled=true" >> "$GITHUB_OUTPUT" + # Deliberately do not echo the endpoints: the claim base is a secret. + echo "NativeLink Cloud enabled: mode=${NL_MODE} exec=${exec_enabled}" diff --git a/.github/actions/test-and-upload-image/action.yaml b/.github/actions/test-and-upload-image/action.yaml index 8c0cb01a5..21bff1073 100644 --- a/.github/actions/test-and-upload-image/action.yaml +++ b/.github/actions/test-and-upload-image/action.yaml @@ -17,24 +17,32 @@ inputs: required: true GHCR_PASSWORD: required: true + force-push: + required: false + default: false runs: using: "composite" steps: + - name: Upgrade registries config to v2 + run: | + echo 'unqualified-search-registries = ["docker.io", "quay.io"]' | sudo tee /etc/containers/registries.conf + shell: bash -euo pipefail {0} + # FIXME: merge the multi-arch and single-arch paths - name: Test multi-arch image - if: ${{ inputs.multi-arch == 'true' && inputs.testing }} + if: ${{ inputs.multi-arch == 'true' && inputs.testing == 'true' }} run: | - nix run --fallback .#create-multi-arch-image localhost:5000 ${{ inputs.image }}:${{ inputs.tag }} ${{ inputs.components }} - nix run --fallback .#local-image-test localhost:5000/${{ inputs.image }}:${{ inputs.tag }} + nix run .#create-multi-arch-image localhost:5000 ${{ inputs.image }}:${{ inputs.tag }} ${{ inputs.components }} + nix run .#local-image-test localhost:5000/${{ inputs.image }}:${{ inputs.tag }} shell: bash -euo pipefail {0} # FIXME: after we've merged this and made sure it all works _then_ remove the 2457 ref # See https://github.com/TraceMachina/nativelink/pull/2457 - name: Upload multi-arch image - if: ${{ inputs.multi-arch == 'true' && contains(fromJson('["refs/heads/main", "refs/pull/2457/merge"]'), github.ref) }} + if: ${{ inputs.multi-arch == 'true' && (inputs.force-push == 'true' || contains(fromJson('["refs/heads/main"]'), github.ref)) }} run: | - nix run --fallback .#regctl-ghcr-login - nix run --fallback .#create-multi-arch-image ghcr.io ${{ github.repository_owner }}/${{ inputs.image }}:${{ inputs.tag }} ${{ inputs.components }} + nix run .#regctl-ghcr-login + nix run .#create-multi-arch-image ghcr.io ${{ github.repository_owner }}/${{ inputs.image }}:${{ inputs.tag }} ${{ inputs.components }} env: # FIXME: When https://github.com/github/roadmap/issues/558 gets fixed, replace with a fine-grained token GHCR_USERNAME: ${{ inputs.GHCR_USERNAME }} @@ -44,15 +52,15 @@ runs: shell: bash -euo pipefail {0} - name: Test image - if: ${{ inputs.multi-arch == 'false' && inputs.testing }} + if: ${{ inputs.multi-arch == 'false' && inputs.testing == 'true' }} run: | - nix run --fallback .#local-image-test ${{ inputs.image }} + nix run .#local-image-test ${{ inputs.image }} shell: bash -euo pipefail {0} - name: Upload image - if: ${{ inputs.multi-arch == 'false' && contains(fromJson('["refs/heads/main", "refs/pull/2457/merge"]'), github.ref) }} + if: ${{ inputs.multi-arch == 'false' && (inputs.force-push == 'true' || contains(fromJson('["refs/heads/main", "refs/pull/2549/merge"]'), github.ref)) }} run: | - nix run --fallback .#publish-ghcr ${{ inputs.image }} + nix run .#publish-ghcr ${{ inputs.image }} ${{ inputs.tag }} env: GHCR_REGISTRY: ghcr.io/${{ github.repository_owner }} GHCR_USERNAME: ${{ inputs.GHCR_USERNAME }} diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ff75e28a6..377e270ce 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,27 +1,36 @@ -# Description + -## Type of change +## What and why -Please delete options that aren't relevant. + -## How Has This Been Tested? +## How was this verified? -Please also list any relevant details for your test configuration + -- [ ] Updated documentation if needed -- [ ] Tests added/amended -- [ ] `bazel test //...` passes locally -- [ ] PR is contained in a single commit, using `git amend` see some [docs](https://www.atlassian.com/git/tutorials/rewriting-history) +## Risk + + diff --git a/.github/scripts/check_pr_body.py b/.github/scripts/check_pr_body.py new file mode 100644 index 000000000..01f9852d5 --- /dev/null +++ b/.github/scripts/check_pr_body.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Check that a pull request body has the template's sections filled in. + +Shape only. Whether a section is empty is something a script can know; +whether it is honest is not, so nothing here tries to judge the content. + +Usage: check_pr_body.py + +Exits 0 when the body is usable, 1 otherwise, printing what is missing in +markdown suitable for posting as a comment. +""" + +import re +import sys + +# Each section a reviewer cannot reconstruct from the diff or from CI. +REQUIRED_SECTIONS = ("What and why", "How was this verified?", "Risk") + +# Long enough to rule out "n/a" and "see title", short enough that one real +# sentence clears it. +MIN_SECTION_CHARS = 40 + +HTML_COMMENT = re.compile(r"", re.DOTALL) + + +def section_body(body: str, heading: str) -> str | None: + """Returns the text under `heading`, or None if the heading is absent.""" + pattern = re.compile( + rf"^\#{{1,6}}\s*{re.escape(heading)}\s*$(.*?)(?=^\#{{1,6}}\s|\Z)", + re.DOTALL | re.MULTILINE | re.IGNORECASE, + ) + match = pattern.search(body) + if match is None: + return None + # Comments are invisible to a reader, so they do not count as content. + return HTML_COMMENT.sub("", match.group(1)).strip() + + +def check(body: str) -> list[str]: + if not body.strip(): + return ["The description is empty. Please fill in the template."] + + problems = [] + for heading in REQUIRED_SECTIONS: + content = section_body(body, heading) + if content is None: + problems.append( + f"**{heading}** is missing. Please keep the template's headings." + ) + elif len(content) < MIN_SECTION_CHARS: + problems.append( + f"**{heading}** needs a bit more detail " + f"({len(content)} characters, {MIN_SECTION_CHARS} expected)." + ) + return problems + + +def main() -> int: + if len(sys.argv) != 2: + print("usage: check_pr_body.py ", file=sys.stderr) + return 2 + + with open(sys.argv[1], encoding="utf-8") as handle: + body = handle.read() + + problems = check(body) + if not problems: + print("Pull request description looks complete.") + return 0 + + print("Some of the pull request description still needs filling in:\n") + for problem in problems: + print(f"- {problem}") + print( + "\nEdit the description and this check re-runs on its own. " + "The sections exist because they are the parts a reviewer cannot get " + "from the diff: why the change is needed, how you know it works, and " + "what breaks if it is wrong." + ) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/styles/config/vocabularies/TraceMachina/accept.txt b/.github/styles/config/vocabularies/TraceMachina/accept.txt index b852843d9..b6e5b8201 100644 --- a/.github/styles/config/vocabularies/TraceMachina/accept.txt +++ b/.github/styles/config/vocabularies/TraceMachina/accept.txt @@ -6,7 +6,10 @@ Astro Bazel Bazelisk [Bb]oolean +[Kk]eyless +Sigstore Cloudflare +[Cc]oalescers? Colab composable CPUs @@ -50,11 +53,10 @@ onboarding OSSF protobuf Recc -Reclient +Siso Rosetta [Rr]epository [Ss]harding -Siso SPDX Starlark Tokio @@ -101,12 +103,11 @@ Config Grafana GitHub Deno -Http +HTTP IPs Noop ONTAP -Redis -redis +[Rr]edis shipstorm hermiticity performant @@ -131,6 +132,7 @@ Datadog Downsampling Brex Citrix +CIQ Menlo benchmarked [Bb]orderless @@ -152,6 +154,8 @@ kubectl [Mm]inikube [Mm]itigations [Pp]recompute +[Pp]repend +[Pp]repending attrs Bzlmod [Dd]eps @@ -170,7 +174,7 @@ impl [Rr]epos rules_cc rules_go -Tls +TLS Zlib backplanes deserialize @@ -287,3 +291,30 @@ gcc [Tt]eardown repo buildbox +subgraph +genrule +hardcoded +shellexpand +pluggable +[Cc]allout +hostnames +prefetch +protos +Serde +camelCase +SDK +varint +prost +unstorable +stdout +args +uncomment +hashmap +Buildbarn +deserialization +Dockerised +Merkle +subtree +hardlink +multiplicatively +SELinux diff --git a/.github/workflows/config-reference.yaml b/.github/workflows/config-reference.yaml new file mode 100644 index 000000000..74eca2d5b --- /dev/null +++ b/.github/workflows/config-reference.yaml @@ -0,0 +1,139 @@ +--- +# Automates step 8 of the release process in CONTRIBUTING.md: when a release +# tag is pushed, regenerate the versioned NativeLink configuration reference +# (web/apps/docs) from that tag and open a PR against main with auto-merge +# enabled. +# +# The generator needs the tag to exist (it builds the config schema from a +# `git worktree` of the tag), which is why this runs on tag push rather than +# on the release PR itself. +# +# Full automation requires two repository settings: +# - "Allow auto-merge" must be enabled (Settings → General). +# - A `WORKFLOW_PR_TOKEN` secret (fine-grained PAT or GitHub App token with +# contents:write + pull-requests:write). PRs created with the default +# GITHUB_TOKEN do not trigger CI workflows, so required checks would never +# report and auto-merge would never fire. Without the secret this workflow +# still opens the PR; it just needs a human to merge it. +name: Regenerate config reference + +on: + push: + tags: + - 'v1.*' + # Manual entry point to (re)generate docs for an existing tag, e.g. to + # backfill a release where this workflow failed. + workflow_dispatch: + inputs: + tag: + description: 'Existing release tag to regenerate the config reference for (e.g. v1.6.1) or blank for all' + required: false # Blank to allow full regen + type: string + # Weekly docs regeneration to catch any cases where we've made updates but haven't changed anything + schedule: + # Sunday 4:13am randomly picked + - cron: 13 4 * * SUN + +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ inputs.tag || github.ref_name }} + cancel-in-progress: false + +jobs: + regenerate: + name: Regenerate and open PR + runs-on: ubuntu-24.04 + timeout-minutes: 60 + permissions: + contents: write + pull-requests: write + id-token: write + steps: + - name: Resolve tag + id: resolve + run: | + set -euo pipefail + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + TAG="${{ inputs.tag }}" + elif [[ "${{ github.event_name }}" == "schedule" ]]; then + TAG= + else + TAG="${{ github.ref_name }}" + fi + if [[ "${TAG}" != "" && "${TAG}" != "main" && ( ! "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ) ]]; then + echo "::error::'${TAG}' is not a release tag (vMAJOR.MINOR.PATCH); refusing to regenerate." + exit 1 + fi + echo "tag=${TAG}" >> "${GITHUB_OUTPUT}" + + - name: Checkout + uses: >- # v6.0.2 + actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + # The docs update lands on main; the generator resolves every + # release tag itself, so it needs the full history and all tags. + ref: main + fetch-depth: 0 + + - name: Prepare Worker + uses: ./.github/actions/prepare-nix + with: + nativelink_attic_token: ${{ secrets.NATIVELINK_ATTIC_TOKEN }} + + - name: Regenerate config reference + working-directory: web + run: | + nix develop --impure --command bash -c " + bun install && bun --filter @nativelink/docs gen:config-reference ${{ steps.resolve.outputs.tag }} + " + + - name: Lint generated docs + run: | + nix develop --impure --command bash -c " + vale web/apps/docs/content/docs/reference/nativelink-config/*.mdx + " + + - name: Open auto-merge PR + env: + GH_TOKEN: ${{ secrets.WORKFLOW_PR_TOKEN || github.token }} + TAG: ${{ steps.resolve.outputs.tag }} + run: | + set -euo pipefail + # The generator also creates new untracked pages (the previous + # latest release gets its own versioned page), so check the whole + # docs tree, not just tracked modifications. + if [[ -z "$(git status --porcelain -- web/apps/docs)" ]]; then + echo "Config reference already up to date for ${TAG}; nothing to do." + exit 0 + fi + + BRANCH="docs/config-reference-${TAG}" + git config user.name "config reference bot" + git config user.email "bot@tracemachina.com" + git switch -c "${BRANCH}" + git add web/apps/docs + git commit -m "docs(config-reference): regenerate for NativeLink ${TAG}" + git push --force origin "${BRANCH}" + + PR_URL=$(gh pr list --head "${BRANCH}" --base main --state open --json url --jq '.[0].url // empty') + if [[ -z "${PR_URL}" ]]; then + PR_URL=$(gh pr create \ + --base main \ + --head "${BRANCH}" \ + --title "docs(config-reference): regenerate for NativeLink ${TAG}" \ + --body "Automated regeneration of the NativeLink configuration reference for ${TAG} (CONTRIBUTING.md release step 8). Generated by the \`${{ github.workflow }}\` workflow.") + fi + echo "PR: ${PR_URL}" + + # Best effort: requires "Allow auto-merge" in the repo settings and, + # with the default GITHUB_TOKEN, required checks never run — see the + # header comment. + gh pr merge --auto --squash "${PR_URL}" || + echo "::notice::Auto-merge could not be enabled; merge ${PR_URL} manually." + + - name: Teardown Worker + uses: ./.github/actions/end-nix + if: always() + with: + nativelink_attic_token: ${{ secrets.NATIVELINK_ATTIC_TOKEN }} diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index d65605b5a..fdf52eeeb 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -41,7 +41,7 @@ jobs: - name: Generate coverage run: | - nix build --fallback -L .#nativelinkCoverageForHost + nix build -L .#nativelinkCoverageForHost cat result/text/index.txt - name: Upload coverage artifact diff --git a/.github/workflows/custom-image.yaml b/.github/workflows/custom-image.yaml index b90c4e909..73827b220 100644 --- a/.github/workflows/custom-image.yaml +++ b/.github/workflows/custom-image.yaml @@ -6,10 +6,10 @@ on: image: description: 'Image to build' required: false - default: 'image' + default: 'nativelink' type: choice options: - - image + - nativelink - nativelink-worker-init - nativelink-worker-lre-cc skip_signing: @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-24.04 permissions: issues: write - pull-requests: read + pull-requests: write outputs: should_build: ${{ steps.check.outputs.should_build }} pr_sha: ${{ steps.check.outputs.pr_sha }} @@ -46,67 +46,78 @@ jobs: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd with: script: | - var fs = require('fs'); - var matrix = JSON.parse(fs.readFileSync('.github/images-matrix.json', 'utf8')); - var validImages = []; - for (const option of matrix['include']) { - validImages.append(option['image']); - } + const fs = require('fs'); + const matrix = JSON.parse(fs.readFileSync('.github/images-matrix.json', 'utf8')); + const validImages = matrix['include'].map((o) => o['image']); + + // Never fail the job over a courtesy comment (e.g. a read-only + // token); the build is what matters. + const tryComment = async (body) => { + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + body, + }); + } catch (e) { + core.warning(`Could not post comment: ${e.message}`); + } + }; + + let image; + let prSha; + if (context.eventName === 'workflow_dispatch') { - core.setOutput('should_build', 'true'); - core.setOutput('pr_sha', context.sha); image = '${{ inputs.image }}'; - } - else if (context.eventName === 'issue_comment') { + prSha = context.sha; + } else if (context.eventName === 'issue_comment') { const body = context.payload.comment.body.trim(); const isPR = !!context.payload.issue.pull_request; - // Match /build-image or /build-image const match = body.match(/^\/build-image(?:\s+(\S+))?/i); - - if (isPR && match) { - const { data: pr } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.issue.number - }); - - const image = match[1] || 'image'; - - if (!validImages.includes(image)) { - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.issue.number, - body: `Unknown image: \`${image}\`\n\nValid options: ${validImages.map(i => `\`${i}\``).join(', ')}` - }); - core.setOutput('should_build', 'false'); - return; - } - - core.setOutput('should_build', 'true'); - core.setOutput('pr_sha', pr.head.sha); - core.setOutput('image', image); - + if (!isPR || !match) { + core.setOutput('should_build', 'false'); + return; + } + image = match[1]; + if (!image || !validImages.includes(image)) { + const hint = image + ? `Unknown image: \`${image}\`` + : 'Specify an image to build.'; + await tryComment( + `${hint}\n\nValid options: ${validImages.map((i) => `\`${i}\``).join(', ')}` + ); + core.setOutput('should_build', 'false'); + return; + } + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.issue.number, + }); + prSha = pr.head.sha; + try { await github.rest.reactions.createForIssueComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: context.payload.comment.id, - content: 'rocket' + content: 'rocket', }); + } catch (e) { + core.warning(`Could not add reaction: ${e.message}`); } } else { core.setOutput('should_build', 'false'); - return + return; } + + const option = matrix['include'].find((o) => o['image'] === image); + core.setOutput('should_build', 'true'); + core.setOutput('pr_sha', prSha); core.setOutput('image', image); - for (const option of matrix['include']) { - if (option['image'] == image) { - core.setOutput('multi-arch', option['multi-arch'] ?? false); - core.setOutput('components', option['components'] ?? ""); - return - } - } + core.setOutput('multi-arch', option?.['multi-arch'] ?? false); + core.setOutput('components', option?.['components'] ?? ''); build-image: name: Build and Push Image @@ -116,6 +127,7 @@ jobs: permissions: contents: read issues: write + pull-requests: write timeout-minutes: 45 steps: - name: Checkout @@ -142,6 +154,7 @@ jobs: tag: ${{ steps.version.outputs.version-string }} GHCR_USERNAME: ${{ vars.GHCR_PUBLISH_USER }} GHCR_PASSWORD: ${{ secrets.GHCR_PUBLISH_TOKEN }} + force-push: true - name: Output image info run: | @@ -154,14 +167,20 @@ jobs: if: github.event_name == 'issue_comment' uses: >- #v8.0.0 actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd + env: + IMAGE_REF: ghcr.io/${{ github.repository_owner }}/${{ needs.check-trigger.outputs.image }}:${{ steps.version.outputs.version-string }} with: script: | - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.issue.number, - body: `Image built and pushed!\n\n\`\`\`\n${{ steps.upload.outputs.image_tag }}\n\`\`\`` - }); + try { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + body: `Image built and pushed!\n\n\`\`\`\n${process.env.IMAGE_REF}\n\`\`\``, + }); + } catch (e) { + core.warning(`Could not post comment: ${e.message}`); + } - name: Teardown Worker uses: ./.github/actions/end-nix diff --git a/.github/workflows/lre.yaml b/.github/workflows/lre.yaml index 16bf40f66..73bb9b276 100644 --- a/.github/workflows/lre.yaml +++ b/.github/workflows/lre.yaml @@ -24,11 +24,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, macos-26] + os: [ubuntu-24.04] toolchain: [lre-cc, lre-rs] - exclude: - - os: macos-26 - toolchain: lre-cc name: Local / ${{ matrix.toolchain }} / ${{ matrix.os }} runs-on: ${{ matrix.os }} timeout-minutes: 45 @@ -42,12 +39,27 @@ jobs: with: nativelink_attic_token: ${{ secrets.NATIVELINK_ATTIC_TOKEN }} + - name: Setup NativeLink Cloud + uses: ./.github/actions/setup-nativelink-cloud + with: + ci-mode: ${{ vars.NATIVELINK_CI_MODE }} + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'push' + && secrets.NATIVELINK_STAGING_API_KEY_RW + || secrets.NATIVELINK_STAGING_API_KEY_RO }} + mode: ${{ github.event_name == 'push' && 'write' || 'read' }} + # Remote execution only on Linux; the action hard-fails exec on + # non-Linux runners, so macOS lanes fall back to cache. + exec: ${{ runner.os == 'Linux' && 'on' || 'off' }} + - name: Build example with ${{ matrix.toolchain }} toolchain env: TOOLCHAIN: ${{ matrix.toolchain }} run: > - nix develop --impure --fallback --command - bash -c "bazel run \ + nix develop --impure --command + bash -c "bazel-retry run \ --lockfile_mode=error \ --verbose_failures \ @local-remote-execution//examples:${TOOLCHAIN}" @@ -88,7 +100,7 @@ jobs: # COMMIT: ${{ github.event.pull_request.head.sha || github.sha }} # TOOLCHAIN: ${{ matrix.toolchain }} # run: | -# nix develop --fallback --impure --command bash -c 'cat > kustomization.yaml << EOF +# nix develop --impure --command bash -c 'cat > kustomization.yaml << EOF # apiVersion: kustomize.config.k8s.io/v1beta1 # kind: Kustomization # resources: diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 2fa5d424d..43dacaf1e 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -94,6 +94,19 @@ jobs: uses: >- # v6.0.2 actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Setup NativeLink Cloud + uses: ./.github/actions/setup-nativelink-cloud + with: + ci-mode: ${{ vars.NATIVELINK_CI_MODE }} + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'push' + && secrets.NATIVELINK_STAGING_API_KEY_RW + || secrets.NATIVELINK_STAGING_API_KEY_RO }} + mode: ${{ github.event_name == 'push' && 'write' || 'read' }} + exec: ${{ runner.os == 'Linux' && 'on' || 'off' }} + - name: Set up Docker Buildx uses: >- # v3.9.0 docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca @@ -107,8 +120,16 @@ jobs: build-args: | OPT_LEVEL=fastbuild ADDITIONAL_BAZEL_FLAGS=--extra_toolchains=@rust_toolchains//:all + secret-files: | + nativelink-bazelrc=user.bazelrc load: true # This brings the build into `docker images` from buildx. tags: trace_machina/nativelink:latest - name: Run tests + env: + # Merges to main are a trusted upload lane; PRs are not (keeps the + # repo-wide --remote_upload_local_results=false anti-poisoning default + # in force for PRs). Upload-dependent integration tests + # (chunking_cache_test, simple_cache_test) self-skip unless this is 1. + NL_LOCAL_UPLOADS: ${{ github.event_name == 'push' && '1' || '0' }} run: ./run_integration_tests.sh diff --git a/.github/workflows/native-bazel.yaml b/.github/workflows/native-bazel.yaml index f6442c6e0..fd60d6eb7 100644 --- a/.github/workflows/native-bazel.yaml +++ b/.github/workflows/native-bazel.yaml @@ -24,10 +24,23 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, macos-26] - name: ${{ matrix.os }} + include: + # Keep the existing required check names on the project-pinned Bazel. + - os: ubuntu-24.04 + bazel_version: 9.1.1 + check_name: ubuntu-24.04 + # Deterministic Bazel compatibility lane. Randomizing Bazel versions + # makes failures harder to reproduce. Bazel 8 cannot read the + # Bazel 9 lockfile format, so this lane tests source compatibility + # without enforcing the committed MODULE.bazel.lock. + - os: ubuntu-24.04 + bazel_version: 8.7.0 + check_name: ubuntu-24.04 / Bazel 8.7.0 + name: ${{ matrix.check_name }} runs-on: ${{ matrix.os }} timeout-minutes: 30 + env: + USE_BAZEL_VERSION: ${{ matrix.bazel_version }} steps: - name: Checkout uses: >- # v6.0.2 @@ -42,15 +55,41 @@ jobs: with: bazelisk-cache: true repository-cache: true - disk-cache: ${{ github.workflow }}-${{ matrix.os }} + disk-cache: ${{ github.workflow }}-${{ matrix.os }}-bazel-${{ matrix.bazel_version }} + + - name: Setup NativeLink Cloud + uses: ./.github/actions/setup-nativelink-cloud + with: + ci-mode: ${{ vars.NATIVELINK_CI_MODE }} + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'push' + && secrets.NATIVELINK_STAGING_API_KEY_RW + || secrets.NATIVELINK_STAGING_API_KEY_RO }} + mode: ${{ github.event_name == 'push' && 'write' || 'read' }} + # Remote execution only on Linux; the action hard-fails exec on + # non-Linux runners, so macOS lanes fall back to cache. + exec: ${{ runner.os == 'Linux' && 'on' || 'off' }} + + - name: Show Bazel version + run: bazel --version - name: Run Bazel tests run: | if [ "$RUNNER_OS" == "Linux" ] || [ "$RUNNER_OS" == "macOS" ]; then - bazel test //... \ - --lockfile_mode=error \ - --extra_toolchains=@rust_toolchains//:all \ - --verbose_failures + if [ "${{ matrix.bazel_version }}" == "8.7.0" ]; then + # Bazel 8 cannot parse the Bazel 9 MODULE.bazel.lock format. + bazel test //... \ + --lockfile_mode=off \ + --extra_toolchains=@rust_toolchains//:all \ + --verbose_failures + else + bazel test //... \ + --lockfile_mode=error \ + --extra_toolchains=@rust_toolchains//:all \ + --verbose_failures + fi elif [ "$RUNNER_OS" == "Windows" ]; then bazel \ --lockfile_mode=error \ @@ -73,6 +112,9 @@ jobs: uses: >- # v6.0.2 actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - name: Free disk space + uses: ./.github/actions/free-disk + - uses: hoverkraft-tech/compose-action@11beaa1c2dae4e8ed7b1665aa074723b6cecb0e4 # v3.0.0 with: compose-file: src/bin/docker-compose.store-tester.yaml @@ -85,6 +127,21 @@ jobs: repository-cache: true disk-cache: ${{ github.workflow }}-ubuntu-24.04 + - name: Setup NativeLink Cloud + uses: ./.github/actions/setup-nativelink-cloud + with: + ci-mode: ${{ vars.NATIVELINK_CI_MODE }} + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'push' + && secrets.NATIVELINK_STAGING_API_KEY_RW + || secrets.NATIVELINK_STAGING_API_KEY_RO }} + mode: ${{ github.event_name == 'push' && 'write' || 'read' }} + # Remote execution only on Linux; the action hard-fails exec on + # non-Linux runners, so macOS lanes fall back to cache. + exec: ${{ runner.os == 'Linux' && 'on' || 'off' }} + - name: Run Store tester with sentinel run: | bazel run //:redis_store_tester \ diff --git a/.github/workflows/native-cargo.yaml b/.github/workflows/native-cargo.yaml index 2b6789598..1bc1a4523 100644 --- a/.github/workflows/native-cargo.yaml +++ b/.github/workflows/native-cargo.yaml @@ -47,8 +47,8 @@ jobs: run: rustup update && rustup default ${{ matrix.toolchain }} - name: Rust cache - # https://github.com/Swatinem/rust-cache/releases/tag/v2.9.1 - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 + uses: >- # v2.9.1 + Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 - name: Build on ${{ runner.os }} run: cargo build --all --profile=smol diff --git a/.github/workflows/nativelink-cloud-canary.yaml b/.github/workflows/nativelink-cloud-canary.yaml new file mode 100644 index 000000000..e75186336 --- /dev/null +++ b/.github/workflows/nativelink-cloud-canary.yaml @@ -0,0 +1,168 @@ +--- +name: NativeLink Cloud Canary + +on: + schedule: + - cron: '17 6 * * *' + workflow_dispatch: + pull_request: + branches: [main] + paths: + - ci.bazelrc + - .github/actions/setup-nativelink-cloud/** + - .github/workflows/nativelink-cloud-canary.yaml + +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + cache-canary: + name: Remote cache canary + runs-on: ubuntu-24.04 + # Also the queue-forever tripwire once an RBE leg is added. + timeout-minutes: 15 + steps: + - name: Checkout + uses: >- # v6.0.2 + actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Setup Bazel + uses: >- # v0.19.0 + bazel-contrib/setup-bazel@c5acdfb288317d0b5c0bbd7a396a3dc868bb0f86 + with: + bazelisk-cache: true + repository-cache: true + # No disk-cache: remote hits must be the only cache signal here. + + - name: Setup NativeLink Cloud + id: nl + uses: ./.github/actions/setup-nativelink-cloud + with: + # The canary ignores vars.NATIVELINK_CI_MODE on purpose: it must + # prove the cloud path is healthy while regular lanes are still + # dark. With no secrets configured (or on fork PRs) it no-ops. + ci-mode: cache + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'pull_request' + && secrets.NATIVELINK_STAGING_API_KEY_RO + || secrets.NATIVELINK_STAGING_API_KEY_RW }} + mode: ${{ github.event_name == 'pull_request' && 'read' || 'write' }} + + - name: Build (populate cache) + if: steps.nl.outputs.enabled == 'true' + run: | + bazel build //nativelink-config/... \ + --lockfile_mode=error \ + --verbose_failures \ + --bes_upload_mode=wait_for_upload_complete + + # The hit-rate assertion needs the populate step to have uploaded, so it + # only runs with the write key (schedule/dispatch/push — never PRs). + - name: Drop local build state + if: steps.nl.outputs.enabled == 'true' && github.event_name != 'pull_request' + run: | + bazel clean + bazel shutdown + + - name: Rebuild and assert remote cache hits + if: steps.nl.outputs.enabled == 'true' && github.event_name != 'pull_request' + run: | + bazel build //nativelink-config/... \ + --lockfile_mode=error \ + --verbose_failures \ + --bes_upload_mode=wait_for_upload_complete \ + --build_event_json_file="$RUNNER_TEMP/bep.json" + + hits=$(jq -s '[.[] | .buildMetrics.actionSummary.runnerCount[]? + | select(.name == "remote cache hit") | .count] | add // 0' \ + "$RUNNER_TEMP/bep.json") + # runnerCount includes an aggregate "total" entry alongside the + # per-runner entries; count only real runners or the rate is halved. + total=$(jq -s '[.[] | .buildMetrics.actionSummary.runnerCount[]? + | select(.name != "internal" and .name != "total") | .count] | add // 0' \ + "$RUNNER_TEMP/bep.json") + invocation=$(jq -rs '[.[] | select(.id.started != null) + | .started.uuid][0] // empty' "$RUNNER_TEMP/bep.json") + action_events=$(jq -s '[.[] + | select(.id.actionCompleted != null)] | length' \ + "$RUNNER_TEMP/bep.json") + target_summaries=$(jq -s '[.[] + | select(.id.targetSummary != null)] | length' \ + "$RUNNER_TEMP/bep.json") + metadata_run_id=$(jq -rs '[.[] + | select(.id.buildMetadata != null) + | .buildMetadata.metadata.GITHUB_RUN_ID][0] // empty' \ + "$RUNNER_TEMP/bep.json") + + echo "Remote cache hits on rebuild: ${hits}/${total} (invocation ${invocation})" + { + echo "### NativeLink Cloud canary" + echo "- Remote cache hits on rebuild: **${hits}/${total}**" + echo "- Invocation: \`${invocation}\`" + echo "- Action events: **${action_events}**" + echo "- Target summaries: **${target_summaries}**" + echo "- Metadata run ID: \`${metadata_run_id}\`" + } >> "$GITHUB_STEP_SUMMARY" + + if [[ "$total" -eq 0 ]]; then + echo "FAIL: no actions were measured; the assertion is vacuous" >&2 + exit 1 + fi + if (( hits * 100 < total * 90 )); then + echo "FAIL: remote cache hit rate below 90% on an unchanged rebuild" >&2 + exit 1 + fi + if [[ "$action_events" -eq 0 ]]; then + echo "FAIL: BEP contains no ActionExecuted events" >&2 + exit 1 + fi + if [[ "$target_summaries" -eq 0 ]]; then + echo "FAIL: BEP contains no TargetSummary events" >&2 + exit 1 + fi + if [[ "$metadata_run_id" != "$GITHUB_RUN_ID" ]]; then + echo "FAIL: BEP is missing the expected GitHub run metadata" >&2 + exit 1 + fi + + # Daily safety net for integration tests that must upload locally-built + # results to the cache (chunking_cache_test, simple_cache_test). The repo-wide + # --remote_upload_local_results=false keeps PR/developer lanes read-only, so + # these tests self-skip unless NL_LOCAL_UPLOADS=1 -- set here (and on merges to + # main in main.yaml). Never runs on PRs: no upload lane, keeps the canary's PR + # leg light. + upload-integration-tests: + name: Upload-dependent integration tests + if: github.event_name != 'pull_request' + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Checkout + uses: >- # v6.0.2 + actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Set up Docker Buildx + uses: >- # v3.9.0 + docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca + + - name: Build image + uses: >- # v6.13.0 + docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 + with: + context: . + file: ./deployment-examples/docker-compose/Dockerfile + build-args: | + OPT_LEVEL=fastbuild + ADDITIONAL_BAZEL_FLAGS=--extra_toolchains=@rust_toolchains//:all + load: true # Brings the image into `docker images` for docker-compose. + tags: trace_machina/nativelink:latest + + - name: Run upload-dependent integration tests + env: + NL_LOCAL_UPLOADS: '1' + run: ./run_integration_tests.sh chunking_cache_test.sh simple_cache_test.sh diff --git a/.github/workflows/nix.yaml b/.github/workflows/nix.yaml index 774adfb1c..1dd19e326 100644 --- a/.github/workflows/nix.yaml +++ b/.github/workflows/nix.yaml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, macos-26] + os: [ubuntu-24.04] name: Bazel Dev / ${{ matrix.os }} runs-on: ${{ matrix.os }} timeout-minutes: 180 @@ -38,33 +38,27 @@ jobs: with: nativelink_attic_token: ${{ secrets.NATIVELINK_ATTIC_TOKEN }} + - name: Setup NativeLink Cloud + uses: ./.github/actions/setup-nativelink-cloud + with: + ci-mode: ${{ vars.NATIVELINK_CI_MODE }} + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'push' + && secrets.NATIVELINK_STAGING_API_KEY_RW + || secrets.NATIVELINK_STAGING_API_KEY_RO }} + mode: ${{ github.event_name == 'push' && 'write' || 'read' }} + # Remote execution only on Linux; the action hard-fails exec on + # non-Linux runners, so macOS lanes fall back to cache. + exec: ${{ runner.os == 'Linux' && 'on' || 'off' }} + - name: Invoke Bazel build in Nix shell run: | - set -o pipefail - - # Bazel's downloader retry only covers truncated downloads, not HTTP 5xx/403 failures, - # so a flaky GitHub fetch aborts the build with no retry. We retry the download in this case. - delay=5 - for attempt in 1 2 3; do - if nix develop --fallback --impure --command \ - bazel test //... \ - --verbose_failures \ - --lockfile_mode=error \ - 2>&1 | tee bazel.log; then - exit 0 - fi - grep -E '^ERROR:' bazel.log \ - | grep -Eq 'GET returned (403|429|5[0-9][0-9])|Bad Gateway|Connection (reset|timed out)|read timed out|Could not resolve host' || { - echo "::error::Bazel failed (non-transient); not retrying." - exit 1 - } - [ "$attempt" -lt 3 ] || break - echo "::warning::Transient fetch error (attempt $attempt); retrying in ${delay}s..." - sleep "$delay" - delay=$((delay * 2)) - done - echo "::error::Bazel still failing after 3 attempts." - exit 1 + nix develop --impure --command \ + bazel-retry test //... \ + --verbose_failures \ + --lockfile_mode=error \ - name: Teardown Worker uses: ./.github/actions/end-nix @@ -76,7 +70,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, macos-26] + os: [ubuntu-24.04] name: Cargo Dev / ${{ matrix.os }} runs-on: ${{ matrix.os }} timeout-minutes: 180 @@ -90,9 +84,13 @@ jobs: with: nativelink_attic_token: ${{ secrets.NATIVELINK_ATTIC_TOKEN }} + - name: Rust cache + uses: >- # v2.9.1 + Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 + - name: Invoke Cargo build in Nix shell run: > - nix develop --fallback --impure --command + nix develop --impure --command bash -c "cargo test --all --profile=smol" - name: Teardown Worker @@ -107,7 +105,6 @@ jobs: matrix: os: - ubuntu-24.04 - - macos-26 name: Installation / ${{ matrix.os }} runs-on: ${{ matrix.os }} timeout-minutes: 180 @@ -123,7 +120,7 @@ jobs: - name: Test nix run run: | - nix run --fallback -L .#nativelink-is-executable-test + nix run -L .#nativelink-is-executable-test - name: Teardown Worker uses: ./.github/actions/end-nix @@ -151,7 +148,7 @@ jobs: - name: Test ${{ matrix.test-name }} run run: | - nix run --fallback -L .#${{ matrix.test-name }}-with-nativelink-test + nix run -L .#${{ matrix.test-name }}-with-nativelink-test - name: Teardown Worker uses: ./.github/actions/end-nix @@ -177,7 +174,7 @@ jobs: - name: Get commands list run: | - COMMANDS=$(nix run --fallback .#rbe-toolchain-with-nativelink-test list) + COMMANDS=$(nix run .#rbe-toolchain-with-nativelink-test list) echo "matrix={\"command\":${COMMANDS}}" >> $GITHUB_OUTPUT id: set-matrix @@ -200,7 +197,7 @@ jobs: - name: Test ${{ matrix.command }} with rbe run: | - nix run --fallback -L .#rbe-toolchain-with-nativelink-test ${{ matrix.command }} + nix run -L .#rbe-toolchain-with-nativelink-test ${{ matrix.command }} - name: Teardown Worker uses: ./.github/actions/end-nix diff --git a/.github/workflows/pr-template-check.yaml b/.github/workflows/pr-template-check.yaml new file mode 100644 index 000000000..1a118b09e --- /dev/null +++ b/.github/workflows/pr-template-check.yaml @@ -0,0 +1,87 @@ +--- +name: PR template + +# `pull_request_target` so the comment can be posted on pull requests from +# forks, which is where a first-time contributor is most likely to need it. +# Nothing from the pull request is checked out or executed: the checkout below +# is the base branch, and the body is only ever read from a file. +on: + pull_request_target: + types: + - opened + - edited + - reopened + - synchronize + - labeled + - unlabeled + +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + check: + name: check + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + pull-requests: write + # Bots never fill in a template, and a maintainer can wave through a + # one-line fix with the skip-pr-template label. + if: >- + github.event.pull_request.user.type != 'Bot' && + !contains(github.event.pull_request.labels.*.name, 'skip-pr-template') + steps: + - name: Checkout + uses: >- # v6.0.2 + actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + + - name: Read the pull request description + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + # Written to a file rather than an env var so the description is never + # interpolated into a shell command. + run: | + gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \ + --json body --jq .body > pr-body.md + + - name: Check the description + id: check + run: | + set +e + python3 .github/scripts/check_pr_body.py pr-body.md > result.md + echo "exit_code=$?" >> "$GITHUB_OUTPUT" + cat result.md + + - name: Leave a comment saying what is missing + if: steps.check.outputs.exit_code != '0' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + # One comment, edited in place, so a few rounds of fixing the + # description does not bury the discussion. + run: | + marker="" + printf '%s\n\n' "$marker" > comment.md + cat result.md >> comment.md + + existing=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \ + --json comments \ + --jq ".comments[] | select(.body | startswith(\"$marker\")) | .url" \ + | head -n 1) + + if [ -n "$existing" ]; then + gh api --method PATCH \ + "repos/$GITHUB_REPOSITORY/issues/comments/${existing##*-}" \ + -f body="$(cat comment.md)" > /dev/null + else + gh pr comment "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \ + --body-file comment.md + fi + + - name: Fail if the description is incomplete + if: steps.check.outputs.exit_code != '0' + run: exit 1 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 000000000..f0fec4e2e --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,214 @@ +--- +# Builds the NativeLink binaries for every supported target, signs each release +# asset with keyless Sigstore cosign, generates an SBOM, and produces SLSA Build +# Level 3 provenance that is attached to the GitHub Release. +# +# This is what the OpenSSF Scorecard "Signed-Releases" check inspects: it reads +# the GitHub Releases API and looks for a cryptographic signature (`*.sig`) plus +# SLSA provenance (`*.intoto.jsonl`) among the release assets. The cosign image +# signatures in GHCR are NOT visible to that check, which is why container-only +# signing left the score at zero. +name: Signed release artifacts + +on: + # Fires automatically the moment a maintainer clicks "Publish release". + release: + types: [published] + # Manual entry point for (re)building and signing assets on an existing + # release tag, e.g. to backfill releases that predate this workflow. + workflow_dispatch: + inputs: + tag: + description: 'Existing release tag to build, sign and attach assets to (e.g. v1.5.2).' + required: true + type: string + +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ github.event.release.tag_name || inputs.tag }} + cancel-in-progress: false + +jobs: + setup: + name: Resolve release tag + runs-on: ubuntu-24.04 + timeout-minutes: 5 + outputs: + tag: ${{ steps.resolve.outputs.tag }} + version: ${{ steps.resolve.outputs.version }} + steps: + - name: Resolve tag and version + id: resolve + run: | + set -euo pipefail + TAG="${{ github.event.release.tag_name || inputs.tag }}" + if [[ -z "${TAG}" ]]; then + echo "::error::No release tag could be determined." + exit 1 + fi + echo "tag=${TAG}" >> "${GITHUB_OUTPUT}" + echo "version=${TAG#v}" >> "${GITHUB_OUTPUT}" + + build: + name: Build ${{ matrix.target }} + needs: setup + permissions: + contents: write # upload assets to the release + id-token: write # keyless cosign signing via Sigstore + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-musl + os: ubuntu-24.04 + attr: nativelink-x86_64-linux + - target: aarch64-unknown-linux-musl + os: ubuntu-24.04 + attr: nativelink-aarch64-linux + - target: aarch64-apple-darwin + os: macos-26 + attr: nativelink-aarch64-darwin + runs-on: ${{ matrix.os }} + timeout-minutes: 90 + env: + GH_TOKEN: ${{ github.token }} + steps: + - name: Checkout ${{ needs.setup.outputs.tag }} + uses: >- # v6.0.2 + actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ needs.setup.outputs.tag }} + persist-credentials: false + + - name: Prepare Worker + uses: ./.github/actions/prepare-nix + with: + nativelink_attic_token: ${{ secrets.NATIVELINK_ATTIC_TOKEN }} + + - name: Install Cosign + uses: >- # v4.1.2 + sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 + with: + # Pin cosign: v3.x forces the new bundle format and drops the legacy + # split signature/certificate output the release assets and verifiers + # depend on. v2.5.3 still emits .sig/.pem files. + cosign-release: v2.5.3 + + - name: Build static binary + run: | + nix build --fallback -L ".#${{ matrix.attr }}" + + - name: Package artifact + id: package + run: | + set -euo pipefail + VERSION="${{ needs.setup.outputs.version }}" + ASSET="nativelink-${VERSION}-${{ matrix.target }}" + + # macOS runners ship `shasum` rather than coreutils `sha256sum`; both + # emit the " " format the SLSA generator expects. + sha256() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" + else + shasum -a 256 "$1" + fi + } + + STAGE="$(mktemp -d)" + install -m 0755 result/bin/nativelink "${STAGE}/nativelink" + install -m 0644 LICENSE "${STAGE}/LICENSE" + install -m 0644 README.md "${STAGE}/README.md" + tar -C "${STAGE}" -czf "${ASSET}.tar.gz" nativelink LICENSE README.md + + sha256 "${ASSET}.tar.gz" | tee "${ASSET}.tar.gz.sha256" + echo "asset=${ASSET}" >> "${GITHUB_OUTPUT}" + + - name: Generate SBOM + uses: >- # v0.24.0 + anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 + with: + file: result/bin/nativelink + format: spdx-json + output-file: ${{ steps.package.outputs.asset }}.spdx.json + upload-artifact: false + upload-release-assets: false + + - name: Sign artifact and SBOM (keyless) + run: | + set -euo pipefail + ASSET="${{ steps.package.outputs.asset }}" + for f in "${ASSET}.tar.gz" "${ASSET}.spdx.json"; do + # Cosign is pinned to v2.5.3 (see the install step) so these flags + # produce the split .sig/.pem files the release assets and verifiers + # expect; --new-bundle-format=false keeps that explicit. + cosign sign-blob --yes \ + --new-bundle-format=false \ + --output-signature "${f}.sig" \ + --output-certificate "${f}.pem" \ + "${f}" + done + + - name: Upload assets to release + run: | + set -euo pipefail + ASSET="${{ steps.package.outputs.asset }}" + gh release upload "${{ needs.setup.outputs.tag }}" \ + "${ASSET}.tar.gz" \ + "${ASSET}.tar.gz.sig" \ + "${ASSET}.tar.gz.pem" \ + "${ASSET}.spdx.json" \ + "${ASSET}.spdx.json.sig" \ + "${ASSET}.spdx.json.pem" \ + --clobber + + - name: Upload hash for provenance + uses: >- # v4.6.0 + actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 + with: + name: sha256-${{ matrix.target }} + path: ${{ steps.package.outputs.asset }}.tar.gz.sha256 + if-no-files-found: error + retention-days: 5 + + combine-hashes: + name: Combine artifact hashes + needs: build + runs-on: ubuntu-24.04 + timeout-minutes: 5 + outputs: + subjects: ${{ steps.hashes.outputs.subjects }} + steps: + - name: Download hashes + uses: >- # v4.3.0 + actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 + with: + pattern: sha256-* + path: hashes + merge-multiple: true + + - name: Combine into base64 subjects + id: hashes + run: | + set -euo pipefail + cat hashes/*.sha256 > combined.sha256 + echo "subjects=$(base64 -w0 < combined.sha256)" >> "${GITHUB_OUTPUT}" + + provenance: + name: Generate SLSA provenance + needs: [setup, combine-hashes] + permissions: + actions: read # read the workflow run to build provenance + id-token: write # keyless signing of the provenance + contents: write # attach provenance to the release + # The SLSA generator MUST be referenced by an immutable semver tag, not a + # commit SHA: slsa-verifier validates the reusable-workflow ref to confirm a + # trusted builder produced the provenance, so a SHA pin would fail + # verification. This is the one intentional exception to SHA-pinning here. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 + with: + base64-subjects: ${{ needs.combine-hashes.outputs.subjects }} + upload-assets: true + upload-tag-name: ${{ needs.setup.outputs.tag }} + provenance-name: nativelink-${{ needs.setup.outputs.version }}.intoto.jsonl diff --git a/.github/workflows/sanitizers.yaml b/.github/workflows/sanitizers.yaml index 0a867f368..3df83fd56 100644 --- a/.github/workflows/sanitizers.yaml +++ b/.github/workflows/sanitizers.yaml @@ -44,5 +44,20 @@ jobs: bazelisk-cache: true repository-cache: true + - name: Setup NativeLink Cloud + uses: ./.github/actions/setup-nativelink-cloud + with: + ci-mode: ${{ vars.NATIVELINK_CI_MODE }} + claim-base: ${{ secrets.NATIVELINK_STAGING_CLAIM_BASE }} + bes-results-url: ${{ secrets.NATIVELINK_STAGING_BES_RESULTS_URL }} + api-key: >- + ${{ github.event_name == 'push' + && secrets.NATIVELINK_STAGING_API_KEY_RW + || secrets.NATIVELINK_STAGING_API_KEY_RO }} + mode: ${{ github.event_name == 'push' && 'write' || 'read' }} + # Remote execution only on Linux; the action hard-fails exec on + # non-Linux runners, so macOS lanes fall back to cache. + exec: ${{ runner.os == 'Linux' && 'on' || 'off' }} + - name: Run Bazel tests run: bazel test --config=${{ matrix.sanitizer }} --lockfile_mode=error --verbose_failures //... diff --git a/.github/workflows/tagged_image.yaml b/.github/workflows/tagged_image.yaml index 7ee1c7138..79822fd0c 100644 --- a/.github/workflows/tagged_image.yaml +++ b/.github/workflows/tagged_image.yaml @@ -53,6 +53,11 @@ jobs: multi-arch: ${{ matrix.multi-arch }} components: ${{ matrix.components }} tag: ${{github.ref_name}} + # This workflow only runs on tag pushes, so github.ref is + # refs/tags/* (never refs/heads/main). Without force-push the upload + # steps in test-and-upload-image are skipped and the tag never gets + # attached to the pushed images. + force-push: true GHCR_USERNAME: ${{ vars.GHCR_PUBLISH_USER }} GHCR_PASSWORD: ${{ secrets.GHCR_PUBLISH_TOKEN }} diff --git a/.github/workflows/web.yaml b/.github/workflows/web.yaml index 50dd2898d..8ecd19e89 100644 --- a/.github/workflows/web.yaml +++ b/.github/workflows/web.yaml @@ -29,7 +29,6 @@ jobs: matrix: os: - ubuntu-24.04 - - macos-26 name: Web Build / ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -51,7 +50,7 @@ jobs: if: github.event_name == 'pull_request' working-directory: web run: | - nix develop --fallback --impure --command bash -c " + nix develop --impure --command bash -c " bun install && bun run build " diff --git a/.gitignore b/.gitignore index 49f46fe80..a2f94dc0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bazel-* +!tools/bazel-retry.sh target/ nativelink-test/fuzz/target/ .vscode/ @@ -27,3 +28,4 @@ user.bazelrc buck-out/ nativelink_config.schema.json .gstack/ +.worktrees/ diff --git a/.vale.ini b/.vale.ini index d6a0112ca..376e5cc25 100644 --- a/.vale.ini +++ b/.vale.ini @@ -12,6 +12,51 @@ IgnoredScopes = code, tt, frontmatter [formats] mdx = md +rs = md + +# FIXME(palfrey): really this should be all our rust code, but that's a lot of changes +# Focusing first on the config bits that get generated into our reference code +# When we do that, we can de-dupe this section and the markdown-specific one +[nativelink-config/src/*.rs] +BasedOnStyles = alex, Vale, Microsoft, write-good + +# Ignore code blocks in Starlight's TabItems. +BlockIgnores = (?s)(.*?```.*?```.*?) + +# Skip URL targets in Markdown links — Vale.Terms shouldn't lint URLs, +# but does by default. The `(?<=\])` lookbehind narrows the pattern so +# it only matches the URL portion of `[link text](url)`. +TokenIgnores = ['"]\.\/[\w-]+\.mdx['"], (?<=\])\([^)]+\) + +# Too harsh. The `write-good.Passive` check already covers many cases. +write-good.E-Prime = NO + +# Redundant. Covered by `write-good.Passive`. +Microsoft.Passive = NO + +# We use typographic em-dashes with spaces for readability. The Microsoft +# style guide wants tight em-dashes; we don't. +Microsoft.Dashes = NO + +# Pedantic style rules we don't want to enforce in technical docs: +Microsoft.Avoid = NO # blanket bans on words like "backend" +Microsoft.HeadingColons = NO # nitpicks heading punctuation +Microsoft.Contractions = NO # "what's" vs "what is" is a tone choice +Microsoft.Foreign = NO # allows "e.g." and "i.e." +Microsoft.Quotes = NO # punctuation-inside-quotes is style +Microsoft.We = NO # we use "we" in conversational tech docs +Microsoft.Negative = NO # en-dash isn't a good idea for negatives + +# Vale's built-in Terms rule does case-sensitive substitution. In tech +# docs, the same word can be a lowercase command (`bazel build`), a +# capitalised proper noun (Bazel), or a path fragment in a URL. Trying +# to enforce one form across all three is noisy and produces false +# positives in code blocks and URLs. +Vale.Terms = NO + +# Microsoft.Auto wants "autodetects" instead of "auto-detects". Both are +# fine in technical prose. +Microsoft.Auto = NO [*.{md,mdx}] BasedOnStyles = alex, Vale, Microsoft, write-good @@ -27,6 +72,14 @@ TokenIgnores = ['"]\.\/[\w-]+\.mdx['"], (?<=\])\([^)]+\) # Ignore filenames and directory names in tree visualizations. BlockIgnores = (?s)(.*?) +# Mermaid diagram source (node ids, `subgraph`/`end` keywords) isn't prose — +# scanning it produces spurious Vale.Repetition hits on short node labels. +BlockIgnores = (?s)(.*?) + +# MDX pages declare metadata via `export const metadata = …` and import +# components; those are code lines, not prose. +BlockIgnores = (?m)^(import|export)\s+.+$ + # Too harsh. The `write-good.Passive` check already covers many cases. write-good.E-Prime = NO diff --git a/BUILD.bazel b/BUILD.bazel index f9a482dea..700ba5dd3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -133,3 +133,12 @@ sh_test( timeout = "short", srcs = [":dummy_test_sh"], ) + +# Large deterministic output used by integration_tests/chunking_cache_test.sh +# to exercise --experimental_remote_cache_chunking (must exceed the chunking +# threshold of 4x the average chunk size). +genrule( + name = "chunking_test_artifact", + outs = ["chunking_test_artifact.txt"], + cmd = "seq 1 1000000 > \"$@\"", +) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45e5b7b3c..0c3eba134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,221 @@ All notable changes to this project will be documented in this file. +## [1.6.4](https://github.com/TraceMachina/nativelink/compare/v1.6.3..1.6.4) - 2026-08-04 + +### ⛰️ Features + +- Add issue templating for more approachable reports ([#2471](https://github.com/TraceMachina/nativelink/issues/2471)) - ([4eb80ad](https://github.com/TraceMachina/nativelink/commit/4eb80ad835753eff8e301d9086afe934930d26b7)) +- Add opt-in zstd wire compression to GrpcStore transfers ([#2596](https://github.com/TraceMachina/nativelink/issues/2596)) - ([64ca974](https://github.com/TraceMachina/nativelink/commit/64ca97402b2ce14fe5fcfe255130bb6b69db827b)) + +### 🐛 Bug Fixes + +- Fix deadlock due to worker resource-tracking leak in scheduler [1.6-patch-1] ([#2642](https://github.com/TraceMachina/nativelink/issues/2642)) - ([7ddf1bd](https://github.com/TraceMachina/nativelink/commit/7ddf1bd1e03b5fff6569bf2e32092f8f6aa65208)) +- Fix duplicate executions of the same action that caused scheduler state to get out of sync [1.6-patch-6] ([#2648](https://github.com/TraceMachina/nativelink/issues/2648)) - ([4278d4b](https://github.com/TraceMachina/nativelink/commit/4278d4b3c15edfc6c269dd240f5bdd884478f1ec)) +- Fix S3 credential discovery over HTTP ([#2651](https://github.com/TraceMachina/nativelink/issues/2651)) - ([58dd792](https://github.com/TraceMachina/nativelink/commit/58dd792e274009b9bf3fc128b2ea3ad9ee8dafe6)) +- *(redis)* skip FT.AGGREGATE rows for docs that expired mid-query ([#2656](https://github.com/TraceMachina/nativelink/issues/2656)) - ([f784549](https://github.com/TraceMachina/nativelink/commit/f784549380576efc3556ad4ec3dd26f244f83e51)) +- *(error)* classify transient Redis failures as retryable ([#2657](https://github.com/TraceMachina/nativelink/issues/2657)) - ([56aa6f7](https://github.com/TraceMachina/nativelink/commit/56aa6f705cb53ebdc7eea2dc5aefc4d5a18e3783)) +- *(worker)* don't abort the worker when a disconnect catches an action in transit ([#2658](https://github.com/TraceMachina/nativelink/issues/2658)) - ([bafafc7](https://github.com/TraceMachina/nativelink/commit/bafafc78f8eddb68201ad76b43641b6bd2f45a35)) + +### 📚 Documentation + +- *(config-reference)* regenerate for NativeLink ([#2652](https://github.com/TraceMachina/nativelink/issues/2652)) - ([4649c50](https://github.com/TraceMachina/nativelink/commit/4649c5034b0e04bce676b9825cb9bd15c52c5c69)) +- Zstd transfers consistency ([#2660](https://github.com/TraceMachina/nativelink/issues/2660)) - ([46a3202](https://github.com/TraceMachina/nativelink/commit/46a32026f2a1a572834f18c8c32108d7dc3496b5)) +- Add GTM to the docs site to improve developer experience ([#2661](https://github.com/TraceMachina/nativelink/issues/2661)) - ([af1bd74](https://github.com/TraceMachina/nativelink/commit/af1bd740f114e768b1a40741ce9b09919026b844)) +- remove NativeLink Cloud product listings and links ([#2637](https://github.com/TraceMachina/nativelink/issues/2637)) - ([d16a1d7](https://github.com/TraceMachina/nativelink/commit/d16a1d70b438f8616c93de96857e2f9a29421d5f)) + +### 🧪 Testing & CI + +- bazel-retry improvements ([#2655](https://github.com/TraceMachina/nativelink/issues/2655)) - ([2c23a86](https://github.com/TraceMachina/nativelink/commit/2c23a867b01b5136af54c0e11baf6b5a2f04909b)) + +### ⚙️ Miscellaneous + +- *(worker)* prevent upload_results deadlock when file count exceeds semaphore permits ([#2636](https://github.com/TraceMachina/nativelink/issues/2636)) ([#2638](https://github.com/TraceMachina/nativelink/issues/2638)) - ([7db3f70](https://github.com/TraceMachina/nativelink/commit/7db3f701323d2bdf1cbb271f499b3d3d2ffdd7f1)) +- Move Github bazel retry into a general command ([#2616](https://github.com/TraceMachina/nativelink/issues/2616)) - ([66055ac](https://github.com/TraceMachina/nativelink/commit/66055ac403391cdeeebcd45204b8b45e1c62171e)) +- Remove the marketing site tracker script ([#2612](https://github.com/TraceMachina/nativelink/issues/2612)) - ([4c2269a](https://github.com/TraceMachina/nativelink/commit/4c2269ac3da9508a07bc2b1b4be9f9c14d8fbdd2)) + +## [1.6.3](https://github.com/TraceMachina/nativelink/compare/v1.6.2..v1.6.3) - 2026-07-24 + +### ⛰️ Features + +- Add GTM to the corporate site ([#2610](https://github.com/TraceMachina/nativelink/issues/2610)) - ([94f312a](https://github.com/TraceMachina/nativelink/commit/94f312a043847d5dd0f8ca95b676b00d4697c04d)) +- Add the Leadfeeder tracker to the marketing site ([#2606](https://github.com/TraceMachina/nativelink/issues/2606)) - ([9700a4a](https://github.com/TraceMachina/nativelink/commit/9700a4a522de525b9121188f19bd1c74b2d4a10e)) +- Prefetch directory-cache tree protos with one GetTree stream ([#2546](https://github.com/TraceMachina/nativelink/issues/2546)) - ([2cbf21e](https://github.com/TraceMachina/nativelink/commit/2cbf21ef52f78ea95d0eb11f9f4396022619b70d)) + +### 🐛 Bug Fixes + +- Fix #2564, .exec cleanup and coun F_FULLFSYNC operations ([#2602](https://github.com/TraceMachina/nativelink/issues/2602)) - ([b44f31d](https://github.com/TraceMachina/nativelink/commit/b44f31dde49cd89210a9d10fdd5414b56db741d1)) +- Fix custom-image workflow: grant pull-requests: write and fix command parsing ([#2600](https://github.com/TraceMachina/nativelink/issues/2600)) - ([63567c8](https://github.com/TraceMachina/nativelink/commit/63567c85b8fc609e47b990336c55b91133069ac1)) +- Let GCS get_part defer NotFound to the retrier ([#2584](https://github.com/TraceMachina/nativelink/issues/2584)) - ([3947c71](https://github.com/TraceMachina/nativelink/commit/3947c71603b5d3acb39d2f0caf2a22db6b009089)) +- Fix skopeo login on ubuntu-24.04 for all image workflows ([#2577](https://github.com/TraceMachina/nativelink/issues/2577)) - ([9717f2f](https://github.com/TraceMachina/nativelink/commit/9717f2fb432c0b8cdd26b078d4851040be64abdd)) + +### 📚 Documentation + +- *(config-reference)* regenerate for NativeLink v1.6.2 ([#2576](https://github.com/TraceMachina/nativelink/issues/2576)) - ([9daa989](https://github.com/TraceMachina/nativelink/commit/9daa989b24330a09f570c623d13331fd293e5062)) +- Move the FAQ into per-page FAQ sections ([#2590](https://github.com/TraceMachina/nativelink/issues/2590)) - ([82a036c](https://github.com/TraceMachina/nativelink/commit/82a036c4a211d6009a251fd47182686f0a2bd85f)) +- Extend the docs FAQ to cover every documentation area ([#2581](https://github.com/TraceMachina/nativelink/issues/2581)) - ([217276c](https://github.com/TraceMachina/nativelink/commit/217276cef05ba5cc2937676b0c874d223a184dac)) +- Redis eviction events support ([#2521](https://github.com/TraceMachina/nativelink/issues/2521)) - ([45a5652](https://github.com/TraceMachina/nativelink/commit/45a56520751e3266be7427bd61950a40eeb49ff0)) + +### 🧪 Testing & CI + +- Skip empty chunks in GCS get_part read stream ([#2620](https://github.com/TraceMachina/nativelink/issues/2620)) - ([41be332](https://github.com/TraceMachina/nativelink/commit/41be33237322c9a67a5431948945b2f7adde3524)) +- Add trace logging for bytestream read ([#2482](https://github.com/TraceMachina/nativelink/issues/2482)) - ([4e2f554](https://github.com/TraceMachina/nativelink/commit/4e2f554f76789edf1072c97db39b8f84906e6a3e)) +- Bootstrap CI on NativeLink Cloud staging (remote cache + BES, dark) ([#2579](https://github.com/TraceMachina/nativelink/issues/2579)) - ([eed5b31](https://github.com/TraceMachina/nativelink/commit/eed5b31e16d2853c2dffddfa107324cd0d7ba0a7)) + +### ⚙️ Miscellaneous + +- Web/compliance and careers ([#2624](https://github.com/TraceMachina/nativelink/issues/2624)) - ([97916b2](https://github.com/TraceMachina/nativelink/commit/97916b2af9b53f0042e7199ace4dfbc6b5c02b95)) +- Replace determinate with nix-quick-install-action ([#2618](https://github.com/TraceMachina/nativelink/issues/2618)) - ([bf908e5](https://github.com/TraceMachina/nativelink/commit/bf908e529eded52fca0a5006e414bb5e333d3be6)) +- add security and trust responsibilities to careers job description ([#2622](https://github.com/TraceMachina/nativelink/issues/2622)) - ([3d40c91](https://github.com/TraceMachina/nativelink/commit/3d40c91a103cc3fa1095f73c4dca13ca64f91f07)) +- Upgrade to rules_rs 0.0.96 ([#2615](https://github.com/TraceMachina/nativelink/issues/2615)) - ([0e7580f](https://github.com/TraceMachina/nativelink/commit/0e7580fcf10d8833e93938d7a76c524a9577fa4e)) +- Increase timeout on trivy ([#2613](https://github.com/TraceMachina/nativelink/issues/2613)) - ([fbf49d6](https://github.com/TraceMachina/nativelink/commit/fbf49d62a660b9bb6e33a7ceb1f4ddb203bd4216)) +- Record the execution metrics that were declared but never emitted ([#2599](https://github.com/TraceMachina/nativelink/issues/2599)) - ([7bb62d7](https://github.com/TraceMachina/nativelink/commit/7bb62d7f2f5b3c0c980b1939c98061204afaca51)) +- Make filesystem store posix_fadvise(DONTNEED) opt-in ([#2608](https://github.com/TraceMachina/nativelink/issues/2608)) - ([d15b2a9](https://github.com/TraceMachina/nativelink/commit/d15b2a97a2d599da520ac12fd45e832dd4f99147)) +- Commit public read-only cache defaults so fork PRs actually receive them ([#2604](https://github.com/TraceMachina/nativelink/issues/2604)) - ([9fe34de](https://github.com/TraceMachina/nativelink/commit/9fe34de2eb6a28b3414fa2e2016c56e657bda279)) +- Skip pre_exec hook when namespaces are disabled to allow posix_spawn ([#2597](https://github.com/TraceMachina/nativelink/issues/2597)) - ([02e3e76](https://github.com/TraceMachina/nativelink/commit/02e3e7665ef566da7eabb10a8d7622d6f0b9dbf3)) +- Coalesce FilesystemStore durability flushes on macOS ([#2539](https://github.com/TraceMachina/nativelink/issues/2539)) - ([97b961a](https://github.com/TraceMachina/nativelink/commit/97b961aac277dd27e0472930a3b1b4733467b8f3)) +- cmake links; rust headers; sandboxing ([#2586](https://github.com/TraceMachina/nativelink/issues/2586)) - ([ddcb47e](https://github.com/TraceMachina/nativelink/commit/ddcb47e5e2c0baaa9537fe5c4be87499f44cde24)) +- Exclude the aggregate total runner entry from the canary hit-rate math ([#2589](https://github.com/TraceMachina/nativelink/issues/2589)) - ([3b1e179](https://github.com/TraceMachina/nativelink/commit/3b1e179b835b03633ee2b42d4ef4fd6627bb57dd)) +- Give fork PRs read-only remote cache via a public key variable ([#2587](https://github.com/TraceMachina/nativelink/issues/2587)) - ([43c0658](https://github.com/TraceMachina/nativelink/commit/43c0658a65e75c073dddf575c3ef6cb8e9afcfe9)) +- cargo-llvm-cov gets flagged, but doesn't have actual vulnerabilities ([#2585](https://github.com/TraceMachina/nativelink/issues/2585)) - ([d59e50f](https://github.com/TraceMachina/nativelink/commit/d59e50f29cff85de3b6194e0bce2a65911830ca4)) +- Cache cargo runs under nix ([#2570](https://github.com/TraceMachina/nativelink/issues/2570)) - ([5ee0afc](https://github.com/TraceMachina/nativelink/commit/5ee0afcfbff2a2393ea3a31b5298e0f38ead1448)) + +### ⬆️ Bumps & Version Updates + +- fix compliance claims, normalize contact emails, add careers pages ([#2621](https://github.com/TraceMachina/nativelink/issues/2621)) - ([b3659b7](https://github.com/TraceMachina/nativelink/commit/b3659b7ee82ad4ffb7bfba6561c3bd10b093e22b)) +- add change history to Terms & Privacy page ([#2619](https://github.com/TraceMachina/nativelink/issues/2619)) - ([c3ffa86](https://github.com/TraceMachina/nativelink/commit/c3ffa86c2ecefeff2cc1afdc2d8bb69230008743)) +- anyhow to 1.0.104 ([#2580](https://github.com/TraceMachina/nativelink/issues/2580)) - ([d1e49ac](https://github.com/TraceMachina/nativelink/commit/d1e49ac5f547006c3ecba9e6a94b16ab82897dce)) +- Update Rust crate syn to v3 ([#2578](https://github.com/TraceMachina/nativelink/issues/2578)) - ([abd0258](https://github.com/TraceMachina/nativelink/commit/abd025888d9b553380ac169f73f802005987749b)) + +## [1.6.2](https://github.com/TraceMachina/nativelink/compare/v1.6.1..v1.6.2) - 2026-07-17 + +### ⛰️ Features + +- Add fallback match interval to simple scheduler ([#2557](https://github.com/TraceMachina/nativelink/issues/2557)) - ([7a4279b](https://github.com/TraceMachina/nativelink/commit/7a4279b4e51cfb6064937b50f763e3c13733db0a)) +- Add opt-in small-blob read coalescing to GrpcStore ([#2540](https://github.com/TraceMachina/nativelink/issues/2540)) - ([4be35e6](https://github.com/TraceMachina/nativelink/commit/4be35e6dccb7fbc08d414ca029c592e9e7853cbf)) + +### 🐛 Bug Fixes + +- Remove quoting around NetApp ([#2556](https://github.com/TraceMachina/nativelink/issues/2556)) - ([65e2ec2](https://github.com/TraceMachina/nativelink/commit/65e2ec2004ca28e3d9273959c7a809f9b0dcb0e0)) +- Fix skopeo login issues on image publish ([#2549](https://github.com/TraceMachina/nativelink/issues/2549)) - ([e72490c](https://github.com/TraceMachina/nativelink/commit/e72490cc3e388a944f177ce47bca46ecbb027180)) +- Handle zero digests in CompressionStore ([#2548](https://github.com/TraceMachina/nativelink/issues/2548)) - ([b08995d](https://github.com/TraceMachina/nativelink/commit/b08995de0447d92fc5a47f71af1d83d4c4da142c)) + +### 📚 Documentation + +- *(config-reference)* regenerate for NativeLink v1.6.0 ([#2553](https://github.com/TraceMachina/nativelink/issues/2553)) - ([f871377](https://github.com/TraceMachina/nativelink/commit/f871377c09ed6fea7538d372e3a3cd2240c231e2)) +- Adds weekly and "everything" docs regen ([#2551](https://github.com/TraceMachina/nativelink/issues/2551)) - ([2a061ba](https://github.com/TraceMachina/nativelink/commit/2a061ba865d2509decc762f11fbdbcf2871d04f9)) +- Remove StoreSpec docs ([#2545](https://github.com/TraceMachina/nativelink/issues/2545)) - ([fb37e86](https://github.com/TraceMachina/nativelink/commit/fb37e86317de19e757ff4e276f2021f9ae0b79cc)) +- Add opt-in subtree-keyed caching to the worker DirectoryCache ([#2541](https://github.com/TraceMachina/nativelink/issues/2541)) - ([9f9451e](https://github.com/TraceMachina/nativelink/commit/9f9451e02cfc1adf0c7830fa4003ab328f894d56)) + +### 🧪 Testing & CI + +- Fix AsyncFixedBuffer with zstd compression, remove unused BufChannelReader adapter ([#2574](https://github.com/TraceMachina/nativelink/issues/2574)) - ([b01cb0d](https://github.com/TraceMachina/nativelink/commit/b01cb0db985a8c5356b58751460981c97bfffd6f)) +- Reject duplicate store names in StoreManager ([#2533](https://github.com/TraceMachina/nativelink/issues/2533)) - ([2106b1a](https://github.com/TraceMachina/nativelink/commit/2106b1a8481c502e7069b2635f39d83a54b37268)) +- Add free-disk to Redis store tester ([#2543](https://github.com/TraceMachina/nativelink/issues/2543)) - ([4b1de2c](https://github.com/TraceMachina/nativelink/commit/4b1de2cf24a86429480235d4641668531ede4e72)) +- Fix flakey MongoDB test ([#2535](https://github.com/TraceMachina/nativelink/issues/2535)) - ([b8e8171](https://github.com/TraceMachina/nativelink/commit/b8e81711a8a5d3048884ef94667415d4afe52a2a)) + +### ⚙️ Miscellaneous + +- Remove more unused items ([#2561](https://github.com/TraceMachina/nativelink/issues/2561)) - ([8a8be18](https://github.com/TraceMachina/nativelink/commit/8a8be1879d70eceff4caf1b73d6ae63c61fddc5d)) +- Don't update config reference without changes ([#2562](https://github.com/TraceMachina/nativelink/issues/2562)) - ([48d9b96](https://github.com/TraceMachina/nativelink/commit/48d9b961e5403a904708e3394eead2a26df30d81)) +- Tag config regen builds to our bot account ([#2554](https://github.com/TraceMachina/nativelink/issues/2554)) - ([5003676](https://github.com/TraceMachina/nativelink/commit/50036764f6e87fe0518f62eb2ee6b2924f7fadd7)) +- Enforce Vale settings for config as well as markdown ([#2552](https://github.com/TraceMachina/nativelink/issues/2552)) - ([27fb8ad](https://github.com/TraceMachina/nativelink/commit/27fb8adde6554de68d452ef87535822ad4330680)) +- curl 8.5.0-2ubuntu10.11 security update ([#2544](https://github.com/TraceMachina/nativelink/issues/2544)) - ([a8e383a](https://github.com/TraceMachina/nativelink/commit/a8e383ae5e8bd78c8b50fdbad17e7376428a3b3e)) + +### ⬆️ Bumps & Version Updates + +- Upgrade anyhow to 1.0.103 for RUSTSEC-2026-0190 ([#2569](https://github.com/TraceMachina/nativelink/issues/2569)) - ([6675acb](https://github.com/TraceMachina/nativelink/commit/6675acb9ed130ee11f174772a0677500944c8049)) +- Upgrade quick-xml to 0.41 for RUSTSEC-2026-0194 ([#2566](https://github.com/TraceMachina/nativelink/issues/2566)) - ([b173e4b](https://github.com/TraceMachina/nativelink/commit/b173e4be5a65abf56e2c0d620aa7ea23b9107900)) +- Upgrade serde_with to 3.21 for GHSA-7gcf-g7xr-8hxj ([#2559](https://github.com/TraceMachina/nativelink/issues/2559)) - ([b18311f](https://github.com/TraceMachina/nativelink/commit/b18311f46f341bf30e4067a04b9ed93866b9bd46)) +- Update nixpkgs so we can drop our patched renovate ([#2537](https://github.com/TraceMachina/nativelink/issues/2537)) - ([ad0d83d](https://github.com/TraceMachina/nativelink/commit/ad0d83dd80d4f1c88f40468722cfb950bd7e87af)) + +## [1.6.1](https://github.com/TraceMachina/nativelink/compare/v1.6.0..v1.6.1) - 2026-07-08 + +### ⛰️ Features + +- Materialize directory-cache nodes concurrently on cold misses ([#2526](https://github.com/TraceMachina/nativelink/issues/2526)) - ([065be46](https://github.com/TraceMachina/nativelink/commit/065be46241cac3509489cadf07a1d33d173e5be5)) +- Marcussorealheis extend zstd ([#2527](https://github.com/TraceMachina/nativelink/issues/2527)) - ([e4b6ca6](https://github.com/TraceMachina/nativelink/commit/e4b6ca6e23ed1e2f460c31cc6f6641fde7016842)) +- Adds timer to hyper ([#2523](https://github.com/TraceMachina/nativelink/issues/2523)) - ([63f3454](https://github.com/TraceMachina/nativelink/commit/63f345431b75b7d16800af1e7676161f4e902b4c)) +- Add REAPI content-defined chunking (SplitBlob/SpliceBlob) support ([#2497](https://github.com/TraceMachina/nativelink/issues/2497)) - ([9d86aaf](https://github.com/TraceMachina/nativelink/commit/9d86aaf97a75c64b8a9c664ab0be0242f2c5a71b)) + +### 🐛 Bug Fixes + +- Flush in detect_duplicate_upload ([#2528](https://github.com/TraceMachina/nativelink/issues/2528)) - ([338abe3](https://github.com/TraceMachina/nativelink/commit/338abe33d1c5b7f15b1a1d9f3dd9dee078cc782b)) + +### 📚 Documentation + +- Fix duplicate phrase in CONTRIBUTING.md ([#2522](https://github.com/TraceMachina/nativelink/issues/2522)) - ([7eaf209](https://github.com/TraceMachina/nativelink/commit/7eaf2090942ee50158dd02fd592bc93958b1ad06)) + +### 🧪 Testing & CI + +- Increase the attic retry time ([#2524](https://github.com/TraceMachina/nativelink/issues/2524)) - ([21dadec](https://github.com/TraceMachina/nativelink/commit/21dadec3357f13ce8e6e9c1a64da6facc5eed7dd)) +- Disable Bazel lockfile in 8.7 compatibility lane ([#2517](https://github.com/TraceMachina/nativelink/issues/2517)) - ([8162a93](https://github.com/TraceMachina/nativelink/commit/8162a935284d770626351c37d531f50b27fb223c)) + +### ⚙️ Miscellaneous + +- *(release)* cross-compile the aarch64 Linux binary on x86 ([#2529](https://github.com/TraceMachina/nativelink/issues/2529)) - ([32e4952](https://github.com/TraceMachina/nativelink/commit/32e4952e82dcdc97cf3b9c1a324ca23c646efcf5)) +- add MCP AI widget, MDX support, and design updates ([#2488](https://github.com/TraceMachina/nativelink/issues/2488)) - ([7909e32](https://github.com/TraceMachina/nativelink/commit/7909e32c4a9bd3ea3f402c397572dd14d5dafbff)) +- Attach the tag to images pushed on a tag build ([#2515](https://github.com/TraceMachina/nativelink/issues/2515)) - ([05c5fac](https://github.com/TraceMachina/nativelink/commit/05c5fac5efdf843b8962bae79a8457c51eb62bd7)) + +### ⬆️ Bumps & Version Updates + +- Upgrade crossbeam-epoch and serial_test ([#2519](https://github.com/TraceMachina/nativelink/issues/2519)) - ([0ac1434](https://github.com/TraceMachina/nativelink/commit/0ac1434f1965bc53d0b28d1cbbfe15f2c4b81acc)) +- Upgrade to Bazel 9.1.1 and 8.7.0 ([#2514](https://github.com/TraceMachina/nativelink/issues/2514)) - ([1f94866](https://github.com/TraceMachina/nativelink/commit/1f9486699a2699d017fa6452619ab79e432702f5)) + +## [1.6.0](https://github.com/TraceMachina/nativelink/compare/v1.5.2..v1.6.0) - 2026-07-06 + +### ⛰️ Features + +- Add troubleshooting tips for macOS Nix setup ([#2505](https://github.com/TraceMachina/nativelink/issues/2505)) - ([5e72a32](https://github.com/TraceMachina/nativelink/commit/5e72a32f2b07f5ce5c6b03eded08c7380999cafe)) +- Regenerate Changelog on New Release ([#2500](https://github.com/TraceMachina/nativelink/issues/2500)) - ([503056f](https://github.com/TraceMachina/nativelink/commit/503056f16ddb13d5aabc76cc54b1af2032f4c384)) +- Add Oracle store ([#2492](https://github.com/TraceMachina/nativelink/issues/2492)) - ([8b74394](https://github.com/TraceMachina/nativelink/commit/8b7439435577a9465ced7229f16664438b607cd3)) +- Improve logging for detect_duplicate_upload and fake redis sync ([#2481](https://github.com/TraceMachina/nativelink/issues/2481)) - ([66f7159](https://github.com/TraceMachina/nativelink/commit/66f7159365cb5009e935d50920d0a5125bc336a8)) +- Add multi-arch images for worker-init ([#2459](https://github.com/TraceMachina/nativelink/issues/2459)) - ([a5b6f65](https://github.com/TraceMachina/nativelink/commit/a5b6f65f45e7c404dfc9233d249aca10eaae587b)) + +### 📚 Documentation + +- *(config-reference)* regenerate for NativeLink v1.5.2 ([#2447](https://github.com/TraceMachina/nativelink/issues/2447)) - ([9ec713c](https://github.com/TraceMachina/nativelink/commit/9ec713c8120b34ea46756a55a42c7079319ecd25)) +- Update the OCI store with the tests and docs ([#2506](https://github.com/TraceMachina/nativelink/issues/2506)) - ([d624f6a](https://github.com/TraceMachina/nativelink/commit/d624f6a483a7b5530506c3ca76d8890bae269239)) +- [web] restore blog posts deleted by the site redesign ([#2501](https://github.com/TraceMachina/nativelink/issues/2501)) - ([6dca947](https://github.com/TraceMachina/nativelink/commit/6dca947a135bea52585ebaa4a627510656e02b62)) +- Update LRE/store docs to fix #2406 ([#2498](https://github.com/TraceMachina/nativelink/issues/2498)) - ([5516d8b](https://github.com/TraceMachina/nativelink/commit/5516d8be1db4045e1d97bede230beab626f0f4e7)) +- Make cleanup wait timeout configurable in LocalWorkerConfig ([#2456](https://github.com/TraceMachina/nativelink/issues/2456)) - ([f25f68d](https://github.com/TraceMachina/nativelink/commit/f25f68d30eab57796a6bf03ef53f28fe04345384)) +- Improve other build systems docs ([#2448](https://github.com/TraceMachina/nativelink/issues/2448)) - ([bc1a294](https://github.com/TraceMachina/nativelink/commit/bc1a29413820c0b402d6f12a1ccfcc66601d3279)) + +### 🧪 Testing & CI + +- Fix custom image building ([#2477](https://github.com/TraceMachina/nativelink/issues/2477)) - ([452a720](https://github.com/TraceMachina/nativelink/commit/452a72035630a08bdd350c2584f210fe8f1cf476)) +- skip writes larger than max_bytes instead of buffering them ([#2473](https://github.com/TraceMachina/nativelink/issues/2473)) - ([1a10e3f](https://github.com/TraceMachina/nativelink/commit/1a10e3fa90c4dd769a3802b7e386b3a0c94fab98)) +- Fix various OCI image upload issues ([#2457](https://github.com/TraceMachina/nativelink/issues/2457)) - ([5f6be36](https://github.com/TraceMachina/nativelink/commit/5f6be36843380e61f6794587557bc5ff25fa3cbc)) +- Improve security scorecard ([#2452](https://github.com/TraceMachina/nativelink/issues/2452)) - ([babdfd9](https://github.com/TraceMachina/nativelink/commit/babdfd9412c45f2018de67f30b0811330c0f2874)) + +### ⚙️ Miscellaneous + +- *(release)* build aarch64 Linux binary on a native arm64 runner ([#2483](https://github.com/TraceMachina/nativelink/issues/2483)) - ([d55e0e5](https://github.com/TraceMachina/nativelink/commit/d55e0e5dc6a4b81e35afc9aa3886f412e28a8702)) +- *(release)* pin cosign to v2.5.3 for legacy .sig/.pem output ([#2480](https://github.com/TraceMachina/nativelink/issues/2480)) - ([1829fa4](https://github.com/TraceMachina/nativelink/commit/1829fa462e6e766b7ac1e5faf74e862925359d8d)) +- *(release)* keep legacy cosign signature/cert outputs ([#2478](https://github.com/TraceMachina/nativelink/issues/2478)) - ([2cd0507](https://github.com/TraceMachina/nativelink/commit/2cd0507b85efd6663bb574f49654e489a9175ea7)) +- *(release)* add signed release artifacts with SLSA provenance ([#2470](https://github.com/TraceMachina/nativelink/issues/2470)) - ([c72bce8](https://github.com/TraceMachina/nativelink/commit/c72bce8533913c70d121c0798f4c6d07ce78537a)) +- Migrate Azure Blob store to use the Azure v1.0 crates ([#2472](https://github.com/TraceMachina/nativelink/issues/2472)) - ([884ffde](https://github.com/TraceMachina/nativelink/commit/884ffdea523ad4ecb00e01c94a7d73cd86edf09a)) +- Remove reclient in favor of Siso ([#2510](https://github.com/TraceMachina/nativelink/issues/2510)) - ([d9325f8](https://github.com/TraceMachina/nativelink/commit/d9325f8cd3d80bb5f22bce03eda5ba3d83693dc6)) +- Strip stray item from changelog ([#2507](https://github.com/TraceMachina/nativelink/issues/2507)) - ([87d16c6](https://github.com/TraceMachina/nativelink/commit/87d16c6a33c4a75add5db499d8a2aa4a84750de1)) +- evict .exec variant when its digest is evicted ([#2474](https://github.com/TraceMachina/nativelink/issues/2474)) ([#2503](https://github.com/TraceMachina/nativelink/issues/2503)) - ([6a162e3](https://github.com/TraceMachina/nativelink/commit/6a162e37cf6315ad76638114129a31521e29356a)) +- Default --fallback for nix rather than having to set it everywhere ([#2475](https://github.com/TraceMachina/nativelink/issues/2475)) - ([f170cdf](https://github.com/TraceMachina/nativelink/commit/f170cdf41326ae9b24e5c0d1b2b344fdd165b4b6)) +- Rename time-based config values to have appropriate postfixes ([#2462](https://github.com/TraceMachina/nativelink/issues/2462)) - ([ccc01eb](https://github.com/TraceMachina/nativelink/commit/ccc01eb6c82584b0564a373d2405df30d389f316)) +- Disable various things we don't want renovate to upgrade ([#2469](https://github.com/TraceMachina/nativelink/issues/2469)) - ([414246b](https://github.com/TraceMachina/nativelink/commit/414246b160c8facf629797b9a95cac4e5a74d8d7)) +- == not != for multi-arch upload ([#2455](https://github.com/TraceMachina/nativelink/issues/2455)) - ([d74ba31](https://github.com/TraceMachina/nativelink/commit/d74ba31dd7a4a6e2c4d50f5594cb558f54f9b077)) +- Multi arch image publish with date-versioning ([#2454](https://github.com/TraceMachina/nativelink/issues/2454)) - ([65d43ed](https://github.com/TraceMachina/nativelink/commit/65d43ede9156caecb704ffb08eea9f6c93bb962f)) +- ref_store now resolves on boot, not first query ([#2451](https://github.com/TraceMachina/nativelink/issues/2451)) - ([0952bb6](https://github.com/TraceMachina/nativelink/commit/0952bb644202b05e82533bbe95eefd2841f4cffc)) + +### ⬆️ Bumps & Version Updates + +- *(web)* Replace hero visual with YouTube video embed ([#2443](https://github.com/TraceMachina/nativelink/issues/2443)) - ([d1863ca](https://github.com/TraceMachina/nativelink/commit/d1863ca3e34e6619b43ee2a55fd6dbf3093253aa)) +- Update dependency marked to v18 ([#2502](https://github.com/TraceMachina/nativelink/issues/2502)) - ([0d516b9](https://github.com/TraceMachina/nativelink/commit/0d516b903054f6fe320767a8c88203137c374c31)) +- Update Rust crate anyhow to v1.0.103 [SECURITY] ([#2494](https://github.com/TraceMachina/nativelink/issues/2494)) - ([d459bd9](https://github.com/TraceMachina/nativelink/commit/d459bd908b96f7cb09d971aeeb7406180a08de58)) +- Update Rust crate opentelemetry_sdk to 0.32.0 [SECURITY] ([#2487](https://github.com/TraceMachina/nativelink/issues/2487)) - ([ce3a919](https://github.com/TraceMachina/nativelink/commit/ce3a919ecce0e6f4ac3ebede5e90813b16f888f8)) +- Update website components ([#2486](https://github.com/TraceMachina/nativelink/issues/2486)) - ([3bfe408](https://github.com/TraceMachina/nativelink/commit/3bfe40897a02853635ba00107d6c193885799eea)) +- bump quinn-proto to 0.11.15 and memmap2 to 0.9.11 (RustSec) ([#2479](https://github.com/TraceMachina/nativelink/issues/2479)) - ([ae5762e](https://github.com/TraceMachina/nativelink/commit/ae5762e5412cede276c37e1f33f6f92788e68dfd)) +- Update dependency @types/node to v26 ([#2453](https://github.com/TraceMachina/nativelink/issues/2453)) - ([a9f5ce1](https://github.com/TraceMachina/nativelink/commit/a9f5ce104f6f0252806884d0608b7f34c27be0f4)) +- Update logo ([#2450](https://github.com/TraceMachina/nativelink/issues/2450)) - ([1989e8d](https://github.com/TraceMachina/nativelink/commit/1989e8d3b0ca274e7e3687c7edab3638c3f90849)) + ## [1.5.2](https://github.com/TraceMachina/nativelink/compare/v1.5.1..v1.5.2) - 2026-06-17 ### 🐛 Bug Fixes @@ -40,10 +255,6 @@ All notable changes to this project will be documented in this file. - Make bash shell scripts actually fall over ([#2428](https://github.com/TraceMachina/nativelink/issues/2428)) - ([d537003](https://github.com/TraceMachina/nativelink/commit/d537003b2eb7ccae69bd126fbec4ea4a9e73aa03)) - worker_utils test coverage to 100% ([#2427](https://github.com/TraceMachina/nativelink/issues/2427)) - ([729c88d](https://github.com/TraceMachina/nativelink/commit/729c88dcf65dd40da4736ddf328fb6a2dbbecd63)) -### ⚙️ Miscellaneous - -- wtf did this come from ([#2434](https://github.com/TraceMachina/nativelink/issues/2434)) - ([6abc5d8](https://github.com/TraceMachina/nativelink/commit/6abc5d87e3127ec8eaf7b8a802c47e2aa3a4f7e2)) - ## [1.5.0](https://github.com/TraceMachina/nativelink/compare/v1.4.0..v1.5.0) - 2026-06-12 ### ⛰️ Features diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48b691c8f..f8644f082 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -201,7 +201,7 @@ NativeLink doesn't allow direct commits or human-created side branches in the ``` 5. Go to https://github.com/TraceMachina/nativelink/pulls where you should see a - button that you can click to create to create a new pull request from your + button that you can click to create a new pull request from your fork to the main repository. 6. Once you opened the pull request, click on the purple `Reviewable` button in @@ -386,6 +386,44 @@ suggestions invoke it directly: vale somefile ``` +## Contributing to Docs or the Website + +The documentation site (docs.nativelink.com) and the marketing site +(nativelink.com) live in the `web/` directory — a Bun + Turborepo workspace +with two Next.js apps: `web/apps/docs` (the docs, built with Fumadocs) and +`web/apps/web` (the website). This replaces the old `web/platform` layout; +the `bun setup`, `bun docs`, and `bun preview` commands from that era no +longer exist. + +The `web/` workspace is **not** part of the Bazel build — it's built with +Bun only. Install Bun (https://bun.sh, or `pkgs.bun` is available in the nix +dev shell), then: + +```bash +cd web +bun install + +# Live dev server for just the docs at http://localhost:3001/docs +bun dev:docs + +# Production build + preview of the docs app +bun --filter @nativelink/docs build +bun --filter @nativelink/docs start # serves the build on port 3001 +``` + +Docs content is MDX under `web/apps/docs/content/docs/`. Every page needs +`title` and `description` frontmatter; sidebar order comes from each +section's `meta.json` (the top-level `content/docs/meta.json` orders the +sections themselves). Authoring conventions, available MDX components, and +style rules are documented on the site itself under +Contribute → [Working on documentation](https://docs.nativelink.com/contribute/docs) +— which is also the page to update if this workflow changes. + +The configuration reference pages under +`web/apps/docs/content/docs/reference/nativelink-config/` are autogenerated +from the Rust config crate — don't edit them by hand; regenerate with +`bun --filter @nativelink/docs gen:config-reference` from `web/`. + ## Creating releases To keep the release process in line with best practices for open source @@ -397,13 +435,42 @@ most automatically generated changelogs provide. - `MODULE.bazel` - `Cargo.toml` - - `nativelink-*/Cargo.toml` + - The `Cargo.toml` of every `nativelink-*` crate — including nested ones + like `nativelink-metric/nativelink-metric-macro-derive/Cargo.toml` — + and the regenerated lock files (`Cargo.lock`, + `nativelink-test/fuzz/Cargo.lock`) + + As a sanity check, a standard release touches 17 files. + +2. Update the changelog by prepending the new release section to the existing + `CHANGELOG.md`. Don't regenerate the whole file — that rewrites previous + release entries and drops manual curation. + + First make sure your local tags match upstream, since `--unreleased` means + "commits not contained in any tag": -2. Run `git cliff --tag=0.x.y > CHANGELOG.md` to update the changelog. You might - need to make manual adjustments to `cliff.toml` if `git-cliff` doesn't put a - commit in the right subsection. + ```bash + git fetch upstream --tags + ``` -3. Create the commit and PR. Call it `Release NativeLink v0.x.y`. + Sanity check which commits will form the new release section: + + ```bash + git log --oneline "$(git describe --tags --abbrev=0)"..HEAD + ``` + + Then prepend the new section: + + ```bash + git cliff --unreleased --tag=v1.x.y --prepend CHANGELOG.md + ``` + + Verify with `git diff CHANGELOG.md` that the change is purely additive: + only added lines, with all previous release entries untouched. You might + need to make manual adjustments to `cliff.toml` if `git-cliff` doesn't put + a commit in the right subsection. + +3. Create the commit and PR. Call it `Release NativeLink v1.x.y`. 4. Once the PR is merged, update your local repository and origin: @@ -418,15 +485,15 @@ most automatically generated changelogs provide. `v` prefix: ```bash - git tag -s v0.x.y + git tag -s v1.x.y - # tag message should be: v0.x.y + # tag message should be: v1.x.y ``` 6. Push the signed tag to the origin repository: ```bash - git push origin v0.x.y + git push origin v1.x.y ``` 7. Pushing the tag triggers an additional GHA workflow which should create the @@ -434,10 +501,17 @@ most automatically generated changelogs provide. the CI job in your fork passes, push the tag to upstream: ```bash - git push upstream v0.x.y + git push upstream v1.x.y ``` 8. Regenerate the latest config reference docs now that the upstream tag exists. + Pushing the tag upstream triggers the + [`Regenerate config reference`](.github/workflows/config-reference.yaml) + workflow, which regenerates the docs and opens a PR against `main` with + auto-merge enabled. Check that the PR appeared and merged; if the workflow + failed, either re-run it from `Actions → Regenerate config reference → Run + workflow` (entering the tag) or fall back to the manual procedure below. + Passing the new tag updates `web/apps/docs/lib/config-versions.ts`, which determines the latest version shown in the docs UI, rewrites `web/apps/docs/content/docs/reference/nativelink-config/index.mdx` from that @@ -447,14 +521,14 @@ most automatically generated changelogs provide. ```bash git fetch --tags upstream cd web - bun --filter @nativelink/docs gen:config-reference v0.x.y + bun --filter @nativelink/docs gen:config-reference v1.x.y cd .. ``` - Confirm that `web/apps/docs/lib/config-versions.ts` marks `v0.x.y` as the + Confirm that `web/apps/docs/lib/config-versions.ts` marks `v1.x.y` as the latest release and that `web/apps/docs/content/docs/reference/nativelink-config/index.mdx` says it was - sourced from `nativelink-config @ v0.x.y`. Then run the docs lint and commit + sourced from `nativelink-config @ v1.x.y`. Then run the docs lint and commit the generated docs update: ```bash @@ -468,6 +542,19 @@ most automatically generated changelogs provide. use previous release notes as template by clicking on the "Edit" button on a previous release and copy-pasting the contents into the new release notes. + Attribute every entry to its author. Keep the same category headings as the + changelog and write each line as ` by @author in (#PR) - (short-sha)`, + then close the notes with a `New Contributors` section and a `Full Changelog` + link. To pull the author list and first-time contributors for the range, run: + + ```bash + gh api -X POST repos/TraceMachina/nativelink/releases/generate-notes \ + -f tag_name=v1.x.y -f previous_tag_name=v1.x.z + ``` + + Fold that output into the categorized notes rather than pasting it verbatim, + since the changelog groups commits by type. + Make sure to include migration instructions for all breaking changes. Explicitly list whatever changes you think are worth mentioning as `Major @@ -476,6 +563,39 @@ most automatically generated changelogs provide. 10. Once all notes are in line, click `Publish Release`. +11. Publishing the release triggers the + [`Signed release artifacts`](.github/workflows/release.yaml) workflow. It + builds the `nativelink` binary for every supported target, signs each asset + with keyless Sigstore cosign, generates an SBOM, and produces SLSA Build + Level 3 provenance, attaching all of it to the GitHub Release. These signed + assets are what the OpenSSF Scorecard `Signed-Releases` check inspects — the + cosign signatures on the GHCR container images are not visible to that check. + + Wait for the workflow to finish, then confirm the release page lists, for + each target, a `*.tar.gz` plus its `*.sig`/`*.pem`, an `*.spdx.json` SBOM, + and a `*.intoto.jsonl` provenance file. You can verify any asset locally: + + ```bash + # Verify the SLSA provenance covers the artifact. + slsa-verifier verify-artifact nativelink-1.x.y-x86_64-unknown-linux-musl.tar.gz \ + --provenance-path nativelink-1.x.y.intoto.jsonl \ + --source-uri github.com/TraceMachina/nativelink \ + --source-tag v1.x.y + + # Verify the cosign signature. + cosign verify-blob nativelink-1.x.y-x86_64-unknown-linux-musl.tar.gz \ + --signature nativelink-1.x.y-x86_64-unknown-linux-musl.tar.gz.sig \ + --certificate nativelink-1.x.y-x86_64-unknown-linux-musl.tar.gz.pem \ + --certificate-identity-regexp '^https://github.com/TraceMachina/nativelink/' \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com + ``` + + If a release ever ships without signed assets (for example a release created + before this workflow existed), re-run the workflow manually against the tag: + `Actions → Signed release artifacts → Run workflow`, entering the tag (e.g. + `v1.x.y`). It will rebuild, re-sign, and attach the assets to that existing + release. + ## Conduct NativeLink Code of Conduct is available in the diff --git a/Cargo.lock b/Cargo.lock index 1cc2205b9..72fb165e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "RustyXML" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b5ace29ee3216de37c0546865ad08edef58b0f9e76838ed8959a84a990e58c5" - [[package]] name = "adler2" version = "2.0.1" @@ -103,9 +97,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "arc-swap" @@ -142,27 +136,38 @@ dependencies = [ ] [[package]] -name = "async-channel" -version = "1.9.0" +name = "async-lock" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", + "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] -name = "async-lock" -version = "3.4.1" +name = "async-stream" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ - "event-listener 5.4.1", - "event-listener-strategy", + "async-stream-impl", + "futures-core", "pin-project-lite", ] +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -171,7 +176,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -214,7 +219,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.4.1", + "fastrand", "hex", "http 1.4.1", "ring", @@ -254,7 +259,7 @@ dependencies = [ "aws-types", "bytes", "bytes-utils", - "fastrand 2.4.1", + "fastrand", "http 0.2.12", "http 1.4.1", "http-body 0.4.6", @@ -286,7 +291,7 @@ dependencies = [ "aws-smithy-xml", "aws-types", "bytes", - "fastrand 2.4.1", + "fastrand", "hex", "hmac", "http 0.2.12", @@ -317,7 +322,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.4.1", + "fastrand", "http 0.2.12", "http 1.4.1", "regex-lite", @@ -341,7 +346,7 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.4.1", + "fastrand", "http 0.2.12", "http 1.4.1", "regex-lite", @@ -366,7 +371,7 @@ dependencies = [ "aws-smithy-types", "aws-smithy-xml", "aws-types", - "fastrand 2.4.1", + "fastrand", "http 0.2.12", "http 1.4.1", "regex-lite", @@ -543,7 +548,7 @@ dependencies = [ "aws-smithy-schema", "aws-smithy-types", "bytes", - "fastrand 2.4.1", + "fastrand", "http 0.2.12", "http 1.4.1", "http-body 0.4.6", @@ -581,7 +586,7 @@ checksum = "8d7396fd9500589e62e460e987ecb671bad374934e55ec3b5f498cc7a8a8a7b7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -689,87 +694,73 @@ dependencies = [ [[package]] name = "azure_core" -version = "0.21.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b552ad43a45a746461ec3d3a51dfb6466b4759209414b439c165eb6a6b7729e" +checksum = "fe6a26a7d374b440015cbbcbf2d9d8be5a133aa940599f5e5dc569504baa262e" dependencies = [ + "async-lock", "async-trait", - "base64 0.22.1", + "azure_core_macros", "bytes", - "dyn-clone", "futures", - "getrandom 0.2.16", - "hmac", - "http-types", - "once_cell", - "paste", "pin-project", - "quick-xml", - "rand 0.8.6", "rustc_version", "serde", "serde_json", - "sha2", - "time", + "tokio", "tracing", - "url", - "uuid", + "typespec", + "typespec_client_core", ] [[package]] -name = "azure_storage" -version = "0.21.0" +name = "azure_core_macros" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f838159f4d29cb400a14d9d757578ba495ae64feb07a7516bf9e4415127126" +checksum = "b9b52dba6a345f3ad2d42ff8d0d63df9d0994cfa29657bf18ffdbf149f78a4f5" dependencies = [ - "RustyXML", - "async-lock", - "async-trait", - "azure_core", - "bytes", - "serde", - "serde_derive", - "time", + "proc-macro2", + "quote", + "syn 2.0.117", "tracing", - "url", - "uuid", ] [[package]] -name = "azure_storage_blobs" -version = "0.21.0" +name = "azure_identity" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e83c3636ae86d9a6a7962b2112e3b19eb3903915c50ce06ff54ff0a2e6a7e4" +checksum = "32edf96b356ca7c51d7590c4925cc36efc3947a5da4468e8e0b25c56ecbb3de5" dependencies = [ - "RustyXML", + "async-lock", + "async-trait", "azure_core", - "azure_storage", - "azure_svc_blobstorage", - "bytes", "futures", + "pin-project", "serde", - "serde_derive", "serde_json", "time", + "tokio", "tracing", "url", - "uuid", ] [[package]] -name = "azure_svc_blobstorage" -version = "0.21.0" +name = "azure_storage_blob" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6c6f20c5611b885ba94c7bae5e02849a267381aecb8aee577e8c35ff4064c6" +checksum = "1756febbcca86c862ef718b983b505d08bd65a9bc984a915b0a16af4a4c3fe5b" dependencies = [ + "async-stream", + "async-trait", "azure_core", "bytes", "futures", - "log", - "once_cell", + "percent-encoding", + "pin-project", "serde", "serde_json", "time", + "tokio", ] [[package]] @@ -778,7 +769,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ - "fastrand 2.4.1", + "fastrand", ] [[package]] @@ -981,12 +972,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chacha20" version = "0.10.0" @@ -1068,7 +1053,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1273,9 +1258,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] @@ -1338,14 +1323,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "darling" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ "darling_core", "darling_macro", @@ -1353,27 +1338,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.117", ] [[package]] name = "darling_macro" -version = "0.21.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1411,7 +1395,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1422,7 +1406,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1435,7 +1419,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.117", ] [[package]] @@ -1456,7 +1440,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.117", "unicode-xid", ] @@ -1507,7 +1491,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1612,12 +1596,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.4.1" @@ -1635,17 +1613,19 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] [[package]] -name = "fastrand" -version = "1.9.0" +name = "fastcdc" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +checksum = "bf51ceb43e96afbfe4dd5c6f6082af5dfd60e220820b8123792d61963f2ce6bc" dependencies = [ - "instant", + "async-stream", + "tokio", + "tokio-stream", ] [[package]] @@ -1803,21 +1783,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-macro" version = "0.3.32" @@ -1826,7 +1791,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1860,16 +1825,16 @@ dependencies = [ [[package]] name = "gcloud-auth" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bdedbc36e6b9d8d79558fbf2ebc098745bc721e9d37d3e369558e420038e360" +checksum = "b43924e3df02cb3b846ca66a7ee58e8c13eb2556d0308c71f6154083f6980365" dependencies = [ "async-trait", "base64 0.22.1", "gcloud-metadata", "home", "jsonwebtoken", - "reqwest 0.12.24", + "reqwest", "serde", "serde_json", "thiserror 2.0.18", @@ -1886,16 +1851,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd3152612316be627be52fe9ca72331eb48425059b3a6a700e7adde223e061d5" dependencies = [ - "reqwest 0.13.4", + "reqwest", "thiserror 2.0.18", "tokio", ] [[package]] name = "gcloud-storage" -version = "1.1.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3515c85ca8d12aaf1104c9765f46d91a9ddd2a62b853fe12db109a40cde06e1" +checksum = "e17f9662a6966402de91daf0edb5accaae05c87f1a85479e57b95d2af7284b9f" dependencies = [ "anyhow", "base64 0.22.1", @@ -1908,7 +1873,7 @@ dependencies = [ "percent-encoding", "pkcs8", "regex", - "reqwest 0.12.24", + "reqwest", "reqwest-middleware", "ring", "serde", @@ -1933,17 +1898,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.16" @@ -1953,7 +1907,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] @@ -1988,8 +1942,7 @@ dependencies = [ [[package]] name = "ginepro" version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b4db47d89cd1f347167b2704df3eeb3ffe1b9afe643fa768a5f8464581921f" +source = "git+https://github.com/mstyura/ginepro?rev=d08cdeff6300edfb46204b3b9fbde3f3355db35f#d08cdeff6300edfb46204b3b9fbde3f3355db35f" dependencies = [ "anyhow", "async-trait", @@ -2239,26 +2192,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-types" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" -dependencies = [ - "anyhow", - "async-channel", - "base64 0.13.1", - "futures-lite", - "infer", - "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", -] - [[package]] name = "httparse" version = "1.10.1" @@ -2316,7 +2249,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.3", ] [[package]] @@ -2350,7 +2282,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2 0.6.4", "tokio", "tower-service", "tracing", @@ -2518,21 +2450,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "infer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "io-lifetimes" version = "2.0.4" @@ -2625,7 +2542,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn", + "syn 2.0.117", ] [[package]] @@ -2650,7 +2567,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2665,11 +2582,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" dependencies = [ - "once_cell", + "cfg-if", + "futures-util", "wasm-bindgen", ] @@ -2780,12 +2698,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "lz4_flex" version = "0.11.6" @@ -2801,7 +2713,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2815,7 +2727,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2826,7 +2738,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2837,7 +2749,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -2873,9 +2785,9 @@ checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "memmap2" -version = "0.9.9" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ "libc", ] @@ -2938,7 +2850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.61.2", ] @@ -3040,7 +2952,7 @@ dependencies = [ "macro_magic", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3051,7 +2963,7 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "nativelink" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", "axum", @@ -3082,7 +2994,7 @@ dependencies = [ [[package]] name = "nativelink-config" -version = "1.5.2" +version = "1.6.4" dependencies = [ "byte-unit", "humantime", @@ -3101,15 +3013,16 @@ dependencies = [ [[package]] name = "nativelink-error" -version = "1.5.2" +version = "1.6.4" dependencies = [ + "base64 0.22.1", "mongodb", "nativelink-metric", "nativelink-proto", "prost", "prost-types", "redis", - "reqwest 0.12.24", + "reqwest", "rustls-pki-types", "serde", "serde_json5", @@ -3124,16 +3037,16 @@ dependencies = [ [[package]] name = "nativelink-macro" -version = "1.5.2" +version = "1.6.4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.1", ] [[package]] name = "nativelink-metric" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", "nativelink-metric-macro-derive", @@ -3144,28 +3057,28 @@ dependencies = [ [[package]] name = "nativelink-metric-macro-derive" -version = "1.5.2" +version = "1.6.4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.1", ] [[package]] name = "nativelink-proto" -version = "1.5.2" +version = "1.6.4" dependencies = [ "derive_more 2.1.0", "prost", - "prost-build", "prost-types", "tonic", - "tonic-build", + "tonic-prost", + "tonic-prost-build", ] [[package]] name = "nativelink-redis-tester" -version = "1.5.2" +version = "1.6.4" dependencies = [ "either", "nativelink-util", @@ -3178,7 +3091,7 @@ dependencies = [ [[package]] name = "nativelink-scheduler" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", "async-trait", @@ -3215,12 +3128,13 @@ dependencies = [ [[package]] name = "nativelink-service" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", "async-trait", "axum", "bytes", + "fastcdc", "futures", "hex", "http-body-util", @@ -3246,16 +3160,19 @@ dependencies = [ "sha2", "tokio", "tokio-stream", + "tokio-util", "tonic", + "tonic-prost", "tower", "tracing", "tracing-test", "uuid", + "zstd", ] [[package]] name = "nativelink-store" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", "async-trait", @@ -3265,8 +3182,8 @@ dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "azure_core", - "azure_storage", - "azure_storage_blobs", + "azure_identity", + "azure_storage_blob", "base64 0.22.1", "blake3", "byteorder", @@ -3308,7 +3225,7 @@ dependencies = [ "redis", "redis-test", "regex", - "reqwest 0.12.24", + "reqwest", "reqwest-middleware", "rlimit", "rustls", @@ -3326,13 +3243,14 @@ dependencies = [ "tracing-test", "url", "uuid", + "webpki-roots 1.0.3", "wincode", "zip", ] [[package]] name = "nativelink-util" -version = "1.5.2" +version = "1.6.4" dependencies = [ "anyhow", "async-trait", @@ -3380,6 +3298,7 @@ dependencies = [ "tokio-stream", "tokio-util", "tonic", + "tonic-prost", "tower", "tracing", "tracing-opentelemetry", @@ -3389,13 +3308,15 @@ dependencies = [ "uuid", "walkdir", "wincode", + "zstd", ] [[package]] name = "nativelink-worker" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", + "async-trait", "bytes", "dunce", "filetime", @@ -3427,6 +3348,7 @@ dependencies = [ "tokio", "tokio-stream", "tonic", + "tonic-prost", "tracing", "tracing-test", "uuid", @@ -3555,23 +3477,22 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "opentelemetry" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6" +checksum = "b0142c63252a9e054e68a4c61a5778f7b14f576274d593f8ce883d191a099682" dependencies = [ "futures-core", "futures-sink", "js-sys", "pin-project-lite", "thiserror 2.0.18", - "tracing", ] [[package]] name = "opentelemetry-appender-tracing" -version = "0.30.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68f63eca5fad47e570e00e893094fc17be959c80c79a7d6ec1abdd5ae6ffc16" +checksum = "2c0080f0dc1d7c786f467cd85a4e395fcab11ee852004f39a29a18ab7c25d837" dependencies = [ "opentelemetry", "tracing", @@ -3581,9 +3502,9 @@ dependencies = [ [[package]] name = "opentelemetry-http" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d" +checksum = "5683015d09e2df236ef005b17f6f196f0d5f6313c4fa43a7b6a53b52776e4331" dependencies = [ "async-trait", "bytes", @@ -3593,9 +3514,9 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b" +checksum = "9966929966d17620d7c316c643ba62631826e10021409357772d5eea84f62c35" dependencies = [ "http 1.4.1", "opentelemetry", @@ -3605,39 +3526,41 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tonic", + "tonic-types", ] [[package]] name = "opentelemetry-proto" -version = "0.30.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc" +checksum = "56d658ba1faf63f7b9c492cfbe6e0ec365440a16132d3270c1065f7b33f1b638" dependencies = [ "opentelemetry", "opentelemetry_sdk", "prost", "tonic", + "tonic-prost", ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d059a296a47436748557a353c5e6c5705b9470ef6c95cfc52c21a8814ddac2" +checksum = "c913ac17a6c451661ee255f4625d143e51647ae78ebd969b75e41c4442f4fe47" [[package]] name = "opentelemetry_sdk" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b" +checksum = "9b59f80e1ac4d5ff7a2db8fb6c80badb7f0f3f858211fba08dd9aaec750894f9" dependencies = [ "futures-channel", "futures-executor", "futures-util", "opentelemetry", "percent-encoding", + "portable-atomic", "rand 0.9.4", - "serde_json", "thiserror 2.0.18", ] @@ -3706,12 +3629,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pastey" version = "0.2.2" @@ -3797,7 +3714,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3812,11 +3729,12 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.7.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", + "hashbrown 0.15.5", "indexmap 2.14.0", ] @@ -3837,7 +3755,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -3937,7 +3855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn", + "syn 2.0.117", ] [[package]] @@ -3960,9 +3878,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", "prost-derive", @@ -3970,111 +3888,55 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" dependencies = [ "heck", "itertools", "log", "multimap", - "once_cell", "petgraph", "prettyplease", "prost", "prost-types", "regex", - "syn", + "syn 2.0.117", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "prost-types" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ "prost", ] [[package]] name = "quick-xml" -version = "0.31.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", "serde", ] -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2 0.5.10", - "thiserror 2.0.18", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.4", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.18", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.5.10", - "tracing", - "windows-sys 0.60.2", -] - [[package]] name = "quote" version = "1.0.45" @@ -4102,19 +3964,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.6" @@ -4147,16 +3996,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -4177,15 +4016,6 @@ dependencies = [ "rand_core 0.9.3", ] -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.4" @@ -4210,15 +4040,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "redis" version = "1.0.0" @@ -4313,7 +4134,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4362,15 +4183,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.24" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", + "h2", "http 1.4.1", "http-body 1.0.1", "http-body-util", @@ -4383,9 +4205,9 @@ dependencies = [ "mime_guess", "percent-encoding", "pin-project-lite", - "quinn", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "serde_urlencoded", @@ -4401,50 +4223,20 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.3", -] - -[[package]] -name = "reqwest" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "http 1.4.1", - "http-body 1.0.1", - "http-body-util", - "hyper", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] name = "reqwest-middleware" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" +checksum = "07bc3f1384cffa4f274dad2d4ddd73aed32fed8f786d96c6be8aa4e5fd3c3b58" dependencies = [ "anyhow", "async-trait", "http 1.4.1", - "reqwest 0.12.24", + "reqwest", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", "tower-service", ] @@ -4526,12 +4318,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustc_version" version = "0.4.1" @@ -4597,7 +4383,6 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" dependencies = [ - "web-time", "zeroize", ] @@ -4660,15 +4445,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scc" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" -dependencies = [ - "sdd", -] - [[package]] name = "schannel" version = "0.1.28" @@ -4712,7 +4488,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn", + "syn 2.0.117", ] [[package]] @@ -4721,12 +4497,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sdd" -version = "3.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" - [[package]] name = "sec1" version = "0.7.3" @@ -4813,7 +4583,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4824,7 +4594,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -4852,17 +4622,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "serde_test" version = "1.0.177" @@ -4886,11 +4645,12 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.15.1" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64 0.22.1", + "bs58", "chrono", "hex", "indexmap 1.9.3", @@ -4905,38 +4665,38 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.15.1" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] name = "serial_test" -version = "3.2.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" dependencies = [ - "futures", + "futures-executor", + "futures-util", "once_cell", "parking_lot", - "scc", "serial_test_derive", ] [[package]] name = "serial_test_derive" -version = "3.2.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5142,6 +4902,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5edbec4ed188954a10c12c038215f8ce7606b2d5c973cd8dc43e8795065c5f2f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -5159,7 +4930,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5217,7 +4988,7 @@ version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "fastrand 2.4.1", + "fastrand", "getrandom 0.3.4", "once_cell", "rustix", @@ -5250,7 +5021,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5261,7 +5032,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5281,7 +5052,6 @@ checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", - "js-sys", "num-conv", "powerfmt", "serde_core", @@ -5373,7 +5143,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5413,9 +5183,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.13.1" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", @@ -5431,9 +5201,9 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", "rustls-native-certs", - "socket2 0.5.10", + "socket2 0.6.4", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-stream", @@ -5446,16 +5216,52 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.13.1" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac6f67be712d12f0b41328db3137e0d0757645d8904b4cb7d51cd9c2279e847" +checksum = "c68f61875ac5293cf72e6c8cf0158086428c82c37229e98c840878f1706b0322" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost", + "tonic", +] + +[[package]] +name = "tonic-prost-build" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654e5643eff75d7f8c99197ce1440ed19a3474eada74c12bbac488b2cafdae27" dependencies = [ "prettyplease", "proc-macro2", "prost-build", "prost-types", "quote", - "syn", + "syn 2.0.117", + "tempfile", + "tonic-build", +] + +[[package]] +name = "tonic-types" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab1b02061f83d519bba3caa167f88f261ef05720ab8ebc954ade70de3348e8" +dependencies = [ + "prost", + "prost-types", + "tonic", ] [[package]] @@ -5526,7 +5332,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5552,14 +5358,12 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.31.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c" +checksum = "adbc64cba7137545b8044cb1fe9814f7aacf3c6b5f9b45be8bb5db538befdb26" dependencies = [ "js-sys", - "once_cell", "opentelemetry", - "opentelemetry_sdk", "smallvec", "tracing", "tracing-core", @@ -5616,7 +5420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5642,7 +5446,7 @@ checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -5657,6 +5461,58 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "typespec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "753a2fe021e407d4fc9ee6f4f0a33403cc306d5c54c4e4ebe1b8cbde0ca052b9" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "quick-xml", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "typespec_client_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924f0c734e0ac3b881ab99d032bd28fcc969d2bb73ef1b8dd4772fd8e518a382" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "dyn-clone", + "futures", + "pin-project", + "rand 0.10.1", + "reqwest", + "serde", + "serde_json", + "time", + "tokio", + "tracing", + "typespec", + "typespec_macros", + "url", + "uuid", +] + +[[package]] +name = "typespec_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c608f4427943f8adb211abc95c87672b1b98847152783507d54e3246e502f60" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + [[package]] name = "ucd-trie" version = "0.1.7" @@ -5718,7 +5574,6 @@ dependencies = [ "idna", "percent-encoding", "serde", - "serde_derive", ] [[package]] @@ -5776,12 +5631,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" -[[package]] -name = "waker-fn" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" - [[package]] name = "walkdir" version = "2.5.0" @@ -5801,12 +5650,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -5833,9 +5676,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" dependencies = [ "cfg-if", "once_cell", @@ -5844,38 +5687,21 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5883,22 +5709,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn", - "wasm-bindgen-backend", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" dependencies = [ "unicode-ident", ] @@ -5927,9 +5753,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -5952,9 +5778,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d" dependencies = [ "js-sys", "wasm-bindgen", @@ -6023,9 +5849,9 @@ dependencies = [ [[package]] name = "wincode" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37095eb18dd6254c66217edc61a29d83d51f8818de8a2ffe88e4584ad73fb5f9" +checksum = "66d967db7705dc29120bb6e8ce5b5a2e27734ed5976d1c904e95bd238d1c3c5a" dependencies = [ "pastey", "proc-macro2", @@ -6036,14 +5862,14 @@ dependencies = [ [[package]] name = "wincode-derive" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e262d55d1261f31e2cfe49cc6385a421d14d99faa0526bbe3cc1bda0d3005c62" +checksum = "15ab90b719560d0fda79c74550ad1c948d17b118765942838055ebaf34d67071" dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6067,7 +5893,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6078,7 +5904,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6383,7 +6209,7 @@ dependencies = [ "heck", "indexmap 2.14.0", "prettyplease", - "syn", + "syn 2.0.117", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -6399,7 +6225,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -6493,7 +6319,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -6514,7 +6340,7 @@ checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -6534,7 +6360,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -6574,7 +6400,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9cf585de2..191f2a00a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ resolver = "2" edition = "2024" name = "nativelink" rust-version = "1.93.1" -version = "1.5.2" +version = "1.6.4" [profile.release] lto = true @@ -75,7 +75,7 @@ tokio = { version = "1.52.2", features = [ tokio-rustls = { version = "0.26.2", default-features = false, features = [ "ring", ] } -tonic = { version = "0.13.0", features = [ +tonic = { version = "0.14.0", features = [ "tls-ring", "transport", ], default-features = false } @@ -94,7 +94,6 @@ serial_test = ["async"] tokio = ["fs", "io-util", "rt-multi-thread", "signal"] tokio-stream = ["fs"] tonic = ["tls", "transport"] -tonic-build = ["prost"] uuid = ["serde", "v4"] [workspace.lints.rust] @@ -132,7 +131,6 @@ missing-abi = "warn" missing-copy-implementations = "warn" missing-debug-implementations = "warn" noop-method-call = "warn" -single-use-lifetimes = "warn" trivial-casts = "warn" trivial-numeric-casts = "warn" unreachable-pub = "warn" @@ -145,15 +143,16 @@ variant-size-differences = "warn" [workspace.lints.clippy] # Global configuration -all = { level = "warn", priority = -1 } -nursery = { level = "warn", priority = -1 } -pedantic = { level = "warn", priority = -1 } +all = { level = "deny", priority = -1 } +nursery = { level = "deny", priority = -1 } +pedantic = { level = "deny", priority = -1 } # Restriction Denies with default priority alloc-instead-of-core = "deny" as-underscore = "deny" await-holding-lock = "deny" bind-instead-of-map = "deny" +cast_possible_wrap = { level = "deny", priority = 1 } collapsible-if = "deny" disallowed-methods = "deny" doc-markdown = "deny" @@ -187,7 +186,6 @@ useless-format = "deny" # Restriction Warnings with default priority dbg-macro = "warn" -decimal-literal-representation = "warn" get-unwrap = "allow" # TODO(jhpratt) Flip missing-docs-in-private-items = "allow" # TODO(jhpratt) Flip unimplemented = "warn" @@ -208,7 +206,6 @@ uninhabited-references = { level = "allow", priority = 1 } # rust-lang/rust # TODO(palfrey): Remove these to get to pedantic. cast_possible_truncation = { level = "deny", priority = 1 } -cast_possible_wrap = { level = "allow", priority = 1 } cast_precision_loss = { level = "allow", priority = 1 } cast_sign_loss = { level = "allow", priority = 1 } large_futures = { level = "allow", priority = 1 } diff --git a/MODULE.bazel b/MODULE.bazel index eae78d033..c9ed3b2c8 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,10 +1,10 @@ module( name = "nativelink", - version = "1.5.2", + version = "1.6.4", compatibility_level = 0, ) -bazel_dep(name = "rules_cc", version = "0.2.18") +bazel_dep(name = "rules_cc", version = "0.2.20") bazel_dep(name = "platforms", version = "1.1.0") bazel_dep(name = "bazel_skylib", version = "1.9.0") bazel_dep(name = "rules_python", version = "2.0.0") @@ -15,7 +15,7 @@ bazel_dep(name = "rules_shell", version = "0.6.1") # via --extra_toolchains, which outranks the MODULE.bazel registration below, # so Nix users keep getting LRE-CC unchanged. Outside Nix (no lre.bazelrc), # these hermetic toolchains replace the host autodetect path. -bazel_dep(name = "llvm", version = "0.7.7") +bazel_dep(name = "llvm", version = "0.8.15") register_toolchains("@llvm//toolchain:all") @@ -50,9 +50,10 @@ register_toolchains( dev_dependency = True, ) -bazel_dep(name = "rules_rs", version = "0.0.76") +bazel_dep(name = "rules_rs", version = "0.0.102") -# Pin rules_rust to the hermeticbuild fork (the same commit rules_rs provisions) +# Pin rules_rust to the hermeticbuild fork +# (see https://github.com/hermeticbuild/rules_rs/blob/v0.0.102/rs/rules_rust.bzl) # so all `@rules_rust//...` references resolve to the patched ruleset. The # bazel_dep + archive_override is the form that keeps `@rules_rust` visible to # subsequent `use_extension(...)` calls in this MODULE.bazel — the alternative @@ -62,15 +63,15 @@ bazel_dep(name = "rules_rs", version = "0.0.76") # The local musl-platforms patch is still applied because the hermeticbuild # fork does not list x86_64/aarch64-unknown-linux-musl as supported triples in # rust/platform/triple_mappings.bzl. -bazel_dep(name = "rules_rust", version = "0.68.1") +bazel_dep(name = "rules_rust", version = "0.71.3") archive_override( module_name = "rules_rust", - integrity = "sha256-HG4cSGKVIoZTn0zpUNKhJbGvFfD2UVPJqKRqgTqLOQQ=", + integrity = "sha256-2Omls/gtvOOdKgmcXazTqrCxf5zegAK6JMSRL/3J51c=", patch_strip = 1, patches = ["//tools:rules_rust-musl-platforms.diff"], - strip_prefix = "rules_rust-cf176d81c12d9c8f6420c7d433b0af0f08d2abb1", + strip_prefix = "rules_rust-f19661ba71f77c993ce1eb082053692610fe4313", urls = [ - "https://github.com/hermeticbuild/rules_rust/archive/cf176d81c12d9c8f6420c7d433b0af0f08d2abb1.tar.gz", + "https://github.com/hermeticbuild/rules_rust/archive/f19661ba71f77c993ce1eb082053692610fe4313.tar.gz", ], ) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 05b9e99cf..a07fc88aa 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -22,7 +22,6 @@ "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4", "https://bcr.bazel.build/modules/apple_support/1.24.2/source.json": "2c22c9827093250406c5568da6c54e6fdf0ef06238def3d99c71b12feb057a8d", "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183", - "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/source.json": "605086bbc197743a0d360f7ddc550a1d4dfa0441bc807236e17170f636153348", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", "https://bcr.bazel.build/modules/bazel_features/1.10.0/MODULE.bazel": "f75e8807570484a99be90abcd52b5e1f390362c258bcb73106f4544957a48101", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", @@ -37,7 +36,6 @@ "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9", "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", - "https://bcr.bazel.build/modules/bazel_features/1.32.0/MODULE.bazel": "095d67022a58cb20f7e20e1aefecfa65257a222c18a938e2914fd257b5f1ccdc", "https://bcr.bazel.build/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6", "https://bcr.bazel.build/modules/bazel_features/1.34.0/MODULE.bazel": "e8475ad7c8965542e0c7aac8af68eb48c4af904be3d614b6aa6274c092c2ea1e", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", @@ -45,7 +43,9 @@ "https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080", "https://bcr.bazel.build/modules/bazel_features/1.43.0/MODULE.bazel": "defa2226f06ba20550d6548c3a2ea2a7929634437a52973869c20c225450eb91", "https://bcr.bazel.build/modules/bazel_features/1.45.0/MODULE.bazel": "7daec6d87ab0703417486d4cb948af0b06f55d4d7c08cbb5978c80e79b538edf", - "https://bcr.bazel.build/modules/bazel_features/1.45.0/source.json": "635e4536e09ff125b8972e0fa239c135fde5f18701f7d5115680560651dfb41d", + "https://bcr.bazel.build/modules/bazel_features/1.47.0/MODULE.bazel": "e34df3cb35b1684cfa69923a61ae3803595babd3942cd306a488d51400886b30", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/MODULE.bazel": "2083ef9c7a469f520890483ccf8e0189d6e71e2117e7752e15e6554433d5ae3e", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/source.json": "e0ee3debde2789ff56e4452e612d126925ba9ab64d4bde79c67f099d2902df9b", "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d", @@ -69,6 +69,8 @@ "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0", "https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f", "https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd", + "https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/MODULE.bazel": "29ecf4babfd3c762be00d7573c288c083672ab60e79c833ff7f49ee662e54471", + "https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/source.json": "8be4a3ef2599693f759e5c0990a4cc5a246ac08db4c900a38f852ba25b5c39be", "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/MODULE.bazel": "f1b7bb2dd53e8f2ef984b39485ec8a44e9076dda5c4b8efd2fb4c6a6e856a31d", "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/source.json": "ebe931bfe362e4b41e59ee00a528db6074157ff2ced92eb9e970acab2e1089c9", "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", @@ -78,12 +80,17 @@ "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.8/MODULE.bazel": "3be7b0faca6f1e69e89197999e0b01ce058c42f3e764ef028466f7e0ff77c761", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.8/source.json": "8403718636114198fca6ea04b437fa001ac7167b4d485102defb0a6f7d11bc08", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", "https://bcr.bazel.build/modules/llvm/0.7.7/MODULE.bazel": "0eeaf1814feca77abc7af3523e2b9d3735f92e2583043f8d6a2cc0fb5f479a28", - "https://bcr.bazel.build/modules/llvm/0.7.7/source.json": "7c8910307329462a21b7bdcc52710360da3de8284738dca52241bb15302a00dc", + "https://bcr.bazel.build/modules/llvm/0.8.15/MODULE.bazel": "2a6f808abd87d6037a435d98816b46ccb4773caa4b1923dea5c02d0a21c9dc19", + "https://bcr.bazel.build/modules/llvm/0.8.15/source.json": "994db3a9052966be153f329219ee9ef163ecbc1e505bbd78079af14c1e24f767", + "https://bcr.bazel.build/modules/llvm/0.8.3/MODULE.bazel": "dbc1bc13171f8f9980a75524883abef1c491613e8d8d805cd4ffa3767ba9708e", + "https://bcr.bazel.build/modules/llvm/0.8.9/MODULE.bazel": "9e35ff5bcac996f9edc1b44b8f8baa58c7855e742c5608b07d925dcdbe642100", "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", "https://bcr.bazel.build/modules/package_metadata/0.0.7/MODULE.bazel": "7adb03933fc8401f495800cf4eafcff0edc6da0ff55c7db223ef69d19f689486", @@ -138,7 +145,9 @@ "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37", "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84", "https://bcr.bazel.build/modules/rules_cc/0.2.18/MODULE.bazel": "4460ec36adc8f722a6a2a4ac9374cb91f2acebadaa93fc37966129afb3dece87", - "https://bcr.bazel.build/modules/rules_cc/0.2.18/source.json": "abad668ff2fd63ada1ac49bf386d37e27048b89a3465a6fd968bb832b00a09d3", + "https://bcr.bazel.build/modules/rules_cc/0.2.19/MODULE.bazel": "d5e0f05b63273281a16654eb6b1a8742a75ec153ac8b4f0419949d6e401e46f0", + "https://bcr.bazel.build/modules/rules_cc/0.2.20/MODULE.bazel": "f5c07bce5ddcb99be21a0812ff5aadb439e688b7449c6542152363b2fd859c1a", + "https://bcr.bazel.build/modules/rules_cc/0.2.20/source.json": "1155433dc6b8161bc339ce94095b337ed95feb1f048b014e10b62339d4b4239c", "https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc", "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", @@ -155,8 +164,8 @@ "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71", "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", - "https://bcr.bazel.build/modules/rules_java/9.0.3/MODULE.bazel": "1f98ed015f7e744a745e0df6e898a7c5e83562d6b759dfd475c76456dda5ccea", - "https://bcr.bazel.build/modules/rules_java/9.0.3/source.json": "b038c0c07e12e658135bbc32cc1a2ded6e33785105c9d41958014c592de4593e", + "https://bcr.bazel.build/modules/rules_java/9.1.0/MODULE.bazel": "ee63f27e36a3fada80342869361182f120a9819c74320e8e65b1e04ba0cd7a9d", + "https://bcr.bazel.build/modules/rules_java/9.1.0/source.json": "da589573c1dee2c9ac4a568b301269a2e8191110ff0345c1a959fa7ea6c4dfd6", "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", @@ -192,8 +201,9 @@ "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", "https://bcr.bazel.build/modules/rules_python/2.0.0/MODULE.bazel": "1459089e2d4194d2a49e07896f5334fb230a8f2966ae945b1f793bef87a292fd", "https://bcr.bazel.build/modules/rules_python/2.0.0/source.json": "b8e25661f58c573e5e27af21295867e87766e89211f326fcb84034e6e6b6794b", - "https://bcr.bazel.build/modules/rules_rs/0.0.76/MODULE.bazel": "461dcf664f368fdc921f67ea20ec1bc78c73f65a0a20b6e2a6d4b1c77fbde8c1", - "https://bcr.bazel.build/modules/rules_rs/0.0.76/source.json": "167eb1122e0f74848fc995b581061155dda1dfd600a38c253a85ef46d0523221", + "https://bcr.bazel.build/modules/rules_rs/0.0.102/MODULE.bazel": "6c64a272531e59dc2a55726117a4ca3161c6301fd69af3bd1038465730e86632", + "https://bcr.bazel.build/modules/rules_rs/0.0.102/source.json": "e0bb950a7126037e2bf5b341e88012fd393d68715489dccce54780f50e6df9ca", + "https://bcr.bazel.build/modules/rules_rs/0.0.82/MODULE.bazel": "fb58eade192a4b957f6e697bdd665861e80acbd504eb1129e84c57cb54f8cba4", "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", @@ -209,13 +219,16 @@ "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/MODULE.bazel": "e8f9ff79199e8d9eaad7f1b0a77ad74b30bb82d794b87d8ca942bead5de83ae9", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/source.json": "20143442376c03426f6135292ba02d825cb75308aa47e6bf42dd4cc5a435c2ff", "https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445", - "https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839", "https://bcr.bazel.build/modules/toolchains_protoc/0.4.3/MODULE.bazel": "54daf5468a9c3e52f6c8a96c8e0b867f7b30029dfe1e74f5a59bf081921d91a3", "https://bcr.bazel.build/modules/toolchains_protoc/0.4.3/source.json": "fbf3886395e08c407caca84f92f8c9ad92b05ce126a94883def1e150edd6b417", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/MODULE.bazel": "b573395fe63aef4299ba095173e2f62ccfee5ad9bbf7acaa95dba73af9fc2b38", "https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/source.json": "3f3fbaeafecaf629877ad152a2c9def21f8d330d91aa94c5dc75bbb98c10b8b8", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.8/MODULE.bazel": "e48a69bd54053c2ec5fffc2a29fb70122afd3e83ab6c07068f63bc6553fa57cc", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.8/source.json": "bd7e928ccd63505b44f4784f7bbf12cc11f9ff23bf3ca12ff2c91cd74846099e", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", @@ -223,30 +236,9 @@ }, "selectedYankedVersions": {}, "moduleExtensions": { - "@@aspect_tools_telemetry+//:extension.bzl%telemetry": { - "general": { - "bzlTransitiveDigest": "MePriaXmQNSqUfE+YQvEtzBc2bU1mjITINIffFiZYgo=", - "usagesDigest": "ibiT5THLv67F8GNR92fjXCqmyYBFE4ZBphBLqWLTFBI=", - "recordedInputs": [ - "REPO_MAPPING:aspect_tools_telemetry+,bazel_lib bazel_lib+", - "REPO_MAPPING:aspect_tools_telemetry+,bazel_skylib bazel_skylib+" - ], - "generatedRepoSpecs": { - "aspect_tools_telemetry_report": { - "repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository", - "attributes": { - "deps": { - "rules_rs": "0.0.76", - "aspect_tools_telemetry": "0.3.3" - } - } - } - } - } - }, "@@local-remote-execution+//rust:extension.bzl%lre_rs": { "general": { - "bzlTransitiveDigest": "Dkt35a5IireKBJP+WmtVzou5W8d/2hLGhl6MJRRA0eg=", + "bzlTransitiveDigest": "uG+JZDxQyPELNihTm54EkV+15PXyp8wI4w/Peu5bXa4=", "usagesDigest": "R9P8gnprFTJ/SsXLiQE5qx+Sqsa8YOFAOmRUyDO3tLY=", "recordedInputs": [ "REPO_MAPPING:local-remote-execution+,bazel_tools bazel_tools" @@ -256,56 +248,56 @@ "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:aarch64-darwin.BUILD.bazel", - "path": "/nix/store/hnaxvxm1n6z37n2zfb9vgknq99xr2jha-rust-default-1.93.1" + "path": "/nix/store/2mchcvza9v1j5mx67r4770plmrkm0f68-rust-default-1.93.1" } }, "lre-rs-nightly-aarch64-darwin": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:aarch64-darwin.BUILD.bazel", - "path": "/nix/store/f3fkv17h8wlnkm026m09vgxyfjhhxp9c-rust-default-1.96.0-nightly-2026-03-24" + "path": "/nix/store/1dysg6qbzyb7vanwsc5y756zmb0227z9-rust-default-1.96.0-nightly-2026-03-24" } }, "lre-rs-stable-aarch64-linux": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:aarch64-linux.BUILD.bazel", - "path": "/nix/store/5vqbs2b3296x8c82xm5scz29n8y2zm0h-rust-default-1.93.1" + "path": "/nix/store/vx2ziqrqc0qj0pjng71cpcyainq52xqd-rust-default-1.93.1" } }, "lre-rs-nightly-aarch64-linux": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:aarch64-linux.BUILD.bazel", - "path": "/nix/store/vji1aridxgaiqrcpagnb6iqf3003b50r-rust-default-1.96.0-nightly-2026-03-24" + "path": "/nix/store/zl02i3a6zzw5mxd665y2n7mp97ajdwkx-rust-default-1.96.0-nightly-2026-03-24" } }, "lre-rs-stable-x86_64-darwin": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:x86_64-darwin.BUILD.bazel", - "path": "/nix/store/kj59hbxsrfsgw3qz5lv3drkhfx2md2sf-rust-default-1.93.1" + "path": "/nix/store/qjpia0l98w7wpf9b3nzfb24y8rxh52cg-rust-default-1.93.1" } }, "lre-rs-nightly-x86_64-darwin": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:x86_64-darwin.BUILD.bazel", - "path": "/nix/store/hqnbzi9zh1jaf957czfs5li266as95bw-rust-default-1.96.0-nightly-2026-03-24" + "path": "/nix/store/wdyvk55ys5m7shpp6jw9d8116m3dlmjd-rust-default-1.96.0-nightly-2026-03-24" } }, "lre-rs-stable-x86_64-linux": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:x86_64-linux.BUILD.bazel", - "path": "/nix/store/1sg0jgxw6k6jy8a3wvfacmnrdii236i0-rust-default-1.93.1" + "path": "/nix/store/cgzz6kbvvhxh4k71rlj9wj14mdbn02n9-rust-default-1.93.1" } }, "lre-rs-nightly-x86_64-linux": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", "attributes": { "build_file": "@@local-remote-execution+//rust:x86_64-linux.BUILD.bazel", - "path": "/nix/store/j7v0r10lpysj1ak70g32rz8rdwbwn5sl-rust-default-1.96.0-nightly-2026-03-24" + "path": "/nix/store/5pysp36qjzbwdjx9zlj9sjc43zhbiwyn-rust-default-1.96.0-nightly-2026-03-24" } } } @@ -313,7 +305,7 @@ }, "@@protobuf+//python/dist:system_python.bzl%system_python_extension": { "general": { - "bzlTransitiveDigest": "yCL9NdIIefY+80P+oAIF4HmY/SRaPmtueyPEL7kVOB8=", + "bzlTransitiveDigest": "pmsA+awieucfllLc2n7k8xEoPp0i5LF9Hw6mGX0cqSQ=", "usagesDigest": "A+RWmbKdBBwZcBbNGNvfPbqG2vYZRjVrFp6x1iRUrAk=", "recordedInputs": [], "generatedRepoSpecs": { @@ -328,11 +320,11 @@ }, "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { "general": { - "bzlTransitiveDigest": "53kgvDiJoicCJNGFz6d2h61Tuh/fKfR+BEDbe+9/8SY=", + "bzlTransitiveDigest": "b+RP7Sgl8KN0VHamrgTqzGLuYPcQ/Mo4ptNkkHUIIlA=", "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=", "recordedInputs": [ "REPO_MAPPING:pybind11_bazel+,bazel_tools bazel_tools", - "FILE:@@pybind11_bazel+//MODULE.bazel 45d98c531db5f8430f847b195357dca36665d9c926cbbee77a85105fc6865d27" + "FILE:@@pybind11_bazel+//MODULE.bazel e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" ], "generatedRepoSpecs": { "pybind11": { @@ -350,7 +342,7 @@ }, "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { - "bzlTransitiveDigest": "ACFsXqVGkz5ZZ1Xi44Dbv+DpY+0T3E98jzGNsvDSONs=", + "bzlTransitiveDigest": "Ga4z8lQy1YQ5rAMy+dOl0dqcCEBnYNCXku8x3YQmDZI=", "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", "recordedInputs": [ "REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools" @@ -407,7 +399,7 @@ }, "@@rules_python+//python/uv:uv.bzl%uv": { "general": { - "bzlTransitiveDigest": "FweP0zel1F17xmT6aBZ3Itw1ogP5QPaaka1Bzndy0Wk=", + "bzlTransitiveDigest": "I8FPZMevE2oI/peSpMBRVIN++WOtfjtJVjbPsBZQ87A=", "usagesDigest": "DwZ4Bamg/skxdi0sa765qXLDi4cL9PQbmLkE7jwQKVU=", "recordedInputs": [ "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", @@ -434,106 +426,6 @@ } } } - }, - "@@rules_rust+//crate_universe/private:internal_extensions.bzl%cu_nr": { - "general": { - "bzlTransitiveDigest": "ZfstfSYBzT+mMfZUBGDjUgj967LyAo5dtVLFDSbphGY=", - "usagesDigest": "w6DeRbiDSXRVPZPJF6BTEEe4fMh1OiL8grDVrOA0M98=", - "recordedInputs": [ - "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", - "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", - "REPO_MAPPING:rules_cc+,bazel_skylib bazel_skylib+", - "REPO_MAPPING:rules_cc+,bazel_tools bazel_tools", - "REPO_MAPPING:rules_cc+,cc_compatibility_proxy rules_cc++compatibility_proxy+cc_compatibility_proxy", - "REPO_MAPPING:rules_cc+,platforms platforms", - "REPO_MAPPING:rules_cc+,rules_cc rules_cc+", - "REPO_MAPPING:rules_cc++compatibility_proxy+cc_compatibility_proxy,rules_cc rules_cc+", - "REPO_MAPPING:rules_rust+,bazel_features bazel_features+", - "REPO_MAPPING:rules_rust+,bazel_skylib bazel_skylib+", - "REPO_MAPPING:rules_rust+,bazel_tools bazel_tools", - "REPO_MAPPING:rules_rust+,cargo_bazel_bootstrap rules_rust++cu_nr+cargo_bazel_bootstrap", - "REPO_MAPPING:rules_rust+,cui rules_rust++cu+cui", - "REPO_MAPPING:rules_rust+,rrc rules_rust++i2+rrc", - "REPO_MAPPING:rules_rust+,rules_cc rules_cc+", - "REPO_MAPPING:rules_rust+,rules_rust rules_rust+" - ], - "generatedRepoSpecs": { - "cargo_bazel_bootstrap": { - "repoRuleId": "@@rules_rust+//cargo/private:cargo_bootstrap.bzl%cargo_bootstrap_repository", - "attributes": { - "srcs": [ - "@@rules_rust+//crate_universe:src/api.rs", - "@@rules_rust+//crate_universe:src/api/lockfile.rs", - "@@rules_rust+//crate_universe:src/cli.rs", - "@@rules_rust+//crate_universe:src/cli/generate.rs", - "@@rules_rust+//crate_universe:src/cli/query.rs", - "@@rules_rust+//crate_universe:src/cli/render.rs", - "@@rules_rust+//crate_universe:src/cli/splice.rs", - "@@rules_rust+//crate_universe:src/cli/vendor.rs", - "@@rules_rust+//crate_universe:src/config.rs", - "@@rules_rust+//crate_universe:src/context.rs", - "@@rules_rust+//crate_universe:src/context/crate_context.rs", - "@@rules_rust+//crate_universe:src/context/platforms.rs", - "@@rules_rust+//crate_universe:src/lib.rs", - "@@rules_rust+//crate_universe:src/lockfile.rs", - "@@rules_rust+//crate_universe:src/main.rs", - "@@rules_rust+//crate_universe:src/metadata.rs", - "@@rules_rust+//crate_universe:src/metadata/cargo_bin.rs", - "@@rules_rust+//crate_universe:src/metadata/cargo_tree_resolver.rs", - "@@rules_rust+//crate_universe:src/metadata/cargo_tree_rustc_wrapper.bat", - "@@rules_rust+//crate_universe:src/metadata/cargo_tree_rustc_wrapper.sh", - "@@rules_rust+//crate_universe:src/metadata/dependency.rs", - "@@rules_rust+//crate_universe:src/metadata/metadata_annotation.rs", - "@@rules_rust+//crate_universe:src/rendering.rs", - "@@rules_rust+//crate_universe:src/rendering/template_engine.rs", - "@@rules_rust+//crate_universe:src/rendering/templates/module_bzl.j2", - "@@rules_rust+//crate_universe:src/rendering/templates/partials/header.j2", - "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/aliases_map.j2", - "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/deps_map.j2", - "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/repo_git.j2", - "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/repo_http.j2", - "@@rules_rust+//crate_universe:src/rendering/templates/vendor_module.j2", - "@@rules_rust+//crate_universe:src/rendering/verbatim/alias_rules.bzl", - "@@rules_rust+//crate_universe:src/select.rs", - "@@rules_rust+//crate_universe:src/splicing.rs", - "@@rules_rust+//crate_universe:src/splicing/cargo_config.rs", - "@@rules_rust+//crate_universe:src/splicing/crate_index_lookup.rs", - "@@rules_rust+//crate_universe:src/splicing/splicer.rs", - "@@rules_rust+//crate_universe:src/test.rs", - "@@rules_rust+//crate_universe:src/utils.rs", - "@@rules_rust+//crate_universe:src/utils/starlark.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/glob.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/label.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/select.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/select_dict.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/select_list.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/select_scalar.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/select_set.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/serialize.rs", - "@@rules_rust+//crate_universe:src/utils/starlark/target_compatible_with.rs", - "@@rules_rust+//crate_universe:src/utils/symlink.rs", - "@@rules_rust+//crate_universe:src/utils/target_triple.rs" - ], - "binary": "cargo-bazel", - "cargo_lockfile": "@@rules_rust+//crate_universe:Cargo.lock", - "cargo_toml": "@@rules_rust+//crate_universe:Cargo.toml", - "version": "1.95.0", - "rust_toolchain_cargo_template": "@rust_host_tools//:bin/{tool}", - "rust_toolchain_rustc_template": "@rust_host_tools//:bin/{tool}", - "compressed_windows_toolchain_names": false, - "timeout": 900 - } - } - }, - "moduleExtensionMetadata": { - "explicitRootModuleDirectDeps": [ - "cargo_bazel_bootstrap" - ], - "explicitRootModuleDirectDevDeps": [], - "useAllRepos": "NO", - "reproducible": false - } - } } }, "facts": { @@ -770,10 +662,11 @@ } }, "@@rules_rs+//rs:extensions.bzl%crate": { - "RustyXML_0.3.0": "{\"dependencies\":[],\"features\":{\"bench\":[]}}", "adler2_2.0.1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[\"std\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[]}}", "ahash_0.8.12": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"const-random\",\"optional\":true,\"req\":\"^0.1.17\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.2\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"hashbrown\",\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.2\"},{\"kind\":\"dev\",\"name\":\"no-panic\",\"req\":\"^0.1.10\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"once_cell\",\"req\":\"^1.18.0\",\"target\":\"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"pcg-mwc\",\"req\":\"^0.2.1\"},{\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"seahash\",\"req\":\"^4.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.59\"},{\"kind\":\"dev\",\"name\":\"smallvec\",\"req\":\"^1.13.1\"},{\"kind\":\"build\",\"name\":\"version_check\",\"req\":\"^0.9.4\"},{\"default_features\":false,\"features\":[\"simd\"],\"name\":\"zerocopy\",\"req\":\"^0.8.24\"}],\"features\":{\"atomic-polyfill\":[\"dep:portable-atomic\",\"once_cell/critical-section\"],\"compile-time-rng\":[\"const-random\"],\"default\":[\"std\",\"runtime-rng\"],\"nightly-arm-aes\":[],\"no-rng\":[],\"runtime-rng\":[\"getrandom\"],\"std\":[]}}", "aho-corasick_1.1.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.3\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"default_features\":false,\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.4.0\"}],\"features\":{\"default\":[\"std\",\"perf-literal\"],\"logging\":[\"dep:log\"],\"perf-literal\":[\"dep:memchr\"],\"std\":[\"memchr?/std\"]}}", + "alloc-no-stdlib_2.0.4": "{\"dependencies\":[],\"features\":{\"unsafe\":[]}}", + "alloc-stdlib_0.2.2": "{\"dependencies\":[{\"name\":\"alloc-no-stdlib\",\"req\":\"^2.0.4\"}],\"features\":{\"unsafe\":[]}}", "allocator-api2_0.2.21": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"fresh-rust\":[],\"nightly\":[],\"std\":[\"alloc\"]}}", "android_system_properties_0.1.5": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.126\"}],\"features\":{}}", "anstream_0.6.21": "{\"dependencies\":[{\"name\":\"anstyle\",\"req\":\"^1.0.0\"},{\"name\":\"anstyle-parse\",\"req\":\"^0.2.0\"},{\"name\":\"anstyle-query\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"anstyle-wincon\",\"optional\":true,\"req\":\"^3.0.5\",\"target\":\"cfg(windows)\"},{\"name\":\"colorchoice\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"divan\",\"req\":\"^0.1.16\"},{\"name\":\"is_terminal_polyfill\",\"req\":\"^1.48\"},{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"owo-colors\",\"req\":\"^4.0.0\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.7.0\"},{\"kind\":\"dev\",\"name\":\"strip-ansi-escapes\",\"req\":\"^0.2.1\"},{\"name\":\"utf8parse\",\"req\":\"^0.2.2\"}],\"features\":{\"auto\":[\"dep:anstyle-query\"],\"default\":[\"auto\",\"wincon\"],\"test\":[],\"wincon\":[\"dep:anstyle-wincon\"]}}", @@ -786,18 +679,21 @@ "anstyle-wincon_3.0.11": "{\"dependencies\":[{\"name\":\"anstyle\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.1\"},{\"name\":\"once_cell_polyfill\",\"req\":\"^1.56.1\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_System_Console\",\"Win32_Foundation\"],\"name\":\"windows-sys\",\"req\":\">=0.60.2, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{}}", "anstyle_1.0.13": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.5\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "anstyle_1.0.14": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.23\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", - "anyhow_1.0.100": "{\"dependencies\":[{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.51\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.6\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "anyhow_1.0.102": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.6\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"backtrace\":[],\"default\":[\"std\"],\"std\":[]}}", + "anyhow_1.0.104": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.6\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"backtrace\":[],\"default\":[\"std\"],\"std\":[]}}", "arc-swap_1.7.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"adaptive-barrier\",\"req\":\"~1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"~0.5\"},{\"kind\":\"dev\",\"name\":\"crossbeam-utils\",\"req\":\"~0.8\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"~1\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"~1\"},{\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"~0.12\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"features\":[\"rc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.130\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.130\"}],\"features\":{\"experimental-strategies\":[],\"experimental-thread-local\":[],\"internal-test-strategies\":[],\"weak\":[]}}", "arcstr_1.2.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7.1\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1\"}],\"features\":{\"default\":[\"substr\"],\"std\":[],\"substr\":[],\"substr-usize-indices\":[\"substr\"]}}", "arrayref_0.3.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"}],\"features\":{}}", "arrayvec_0.7.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.4\"},{\"default_features\":false,\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"matches\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.4\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "ascii_1.1.0": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"name\":\"serde_test\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "assert-json-diff_2.0.2": "{\"dependencies\":[{\"name\":\"serde\",\"req\":\"^1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"version-sync\",\"req\":\"^0.8\"}],\"features\":{}}", - "async-channel_1.9.0": "{\"dependencies\":[{\"name\":\"concurrent-queue\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"easy-parallel\",\"req\":\"^3\"},{\"name\":\"event-listener\",\"req\":\"^2.4.0\"},{\"name\":\"futures-core\",\"req\":\"^0.3.5\"},{\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^1\"}],\"features\":{}}", "async-lock_3.4.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"event-listener\",\"req\":\"^5.0.0\"},{\"default_features\":false,\"name\":\"event-listener-strategy\",\"req\":\"^0.5.0\"},{\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"flume\",\"req\":\"^0.11.0\"},{\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2.0.0\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"kind\":\"dev\",\"name\":\"waker-fn\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"}],\"features\":{\"default\":[\"std\"],\"loom\":[\"event-listener/loom\",\"dep:loom\"],\"std\":[\"event-listener/std\",\"event-listener-strategy/std\"]}}", + "async-stream-impl_0.3.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"}],\"features\":{}}", + "async-stream_0.3.6": "{\"dependencies\":[{\"name\":\"async-stream-impl\",\"req\":\"=0.3.6\"},{\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1\"}],\"features\":{}}", "async-trait_0.1.89": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.30\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"full\",\"parsing\",\"printing\",\"proc-macro\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.46\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.40\"},{\"kind\":\"dev\",\"name\":\"tracing-attributes\",\"req\":\"^0.1.27\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.81\"}],\"features\":{}}", "atomic-waker_1.1.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"cargo_bench_support\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.7.0\"}],\"features\":{}}", "atomic_0.6.1": "{\"dependencies\":[{\"name\":\"bytemuck\",\"req\":\"^1.13.1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.13.1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.219\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.219\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.140\"}],\"features\":{\"default\":[\"fallback\"],\"fallback\":[],\"nightly\":[],\"serde\":[\"dep:serde\"],\"std\":[]}}", + "autocfg_1.5.0": "{\"dependencies\":[],\"features\":{}}", "autocfg_1.5.1": "{\"dependencies\":[],\"features\":{}}", "aws-config_1.8.14": "{\"dependencies\":[{\"features\":[\"test-util\"],\"name\":\"aws-credential-types\",\"req\":\"^1.2.12\"},{\"name\":\"aws-runtime\",\"req\":\"^1.7.0\"},{\"default_features\":false,\"name\":\"aws-sdk-signin\",\"optional\":true,\"req\":\"^1.5.0\"},{\"default_features\":false,\"name\":\"aws-sdk-sso\",\"optional\":true,\"req\":\"^1.94.0\"},{\"default_features\":false,\"name\":\"aws-sdk-ssooidc\",\"optional\":true,\"req\":\"^1.96.0\"},{\"default_features\":false,\"name\":\"aws-sdk-sts\",\"req\":\"^1.98.0\"},{\"name\":\"aws-smithy-async\",\"req\":\"^1.2.12\"},{\"features\":[\"rt-tokio\",\"test-util\"],\"kind\":\"dev\",\"name\":\"aws-smithy-async\",\"req\":\"^1.2.12\"},{\"name\":\"aws-smithy-http\",\"req\":\"^0.63.4\"},{\"features\":[\"default-client\",\"test-util\"],\"kind\":\"dev\",\"name\":\"aws-smithy-http-client\",\"req\":\"^1.1.10\"},{\"name\":\"aws-smithy-json\",\"req\":\"^0.62.4\"},{\"features\":[\"client\"],\"name\":\"aws-smithy-runtime\",\"req\":\"^1.10.1\"},{\"features\":[\"client\",\"test-util\"],\"kind\":\"dev\",\"name\":\"aws-smithy-runtime\",\"req\":\"^1.10.1\"},{\"features\":[\"client\"],\"name\":\"aws-smithy-runtime-api\",\"req\":\"^1.11.4\"},{\"features\":[\"test-util\"],\"kind\":\"dev\",\"name\":\"aws-smithy-runtime-api\",\"req\":\"^1.11.4\"},{\"name\":\"aws-smithy-types\",\"req\":\"^1.4.4\"},{\"name\":\"aws-types\",\"req\":\"^1.3.12\"},{\"name\":\"base64-simd\",\"optional\":true,\"req\":\"^0.8.0\"},{\"name\":\"bytes\",\"req\":\"^1.1.0\"},{\"name\":\"fastrand\",\"req\":\"^2.3.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.29\"},{\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"name\":\"p256\",\"optional\":true,\"req\":\"^0.13.2\"},{\"default_features\":false,\"features\":[\"std\",\"std_rng\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8.5\"},{\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17.5\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10.9\"},{\"features\":[\"parsing\"],\"name\":\"time\",\"req\":\"^0.3.4\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"req\":\"^1.13.1\"},{\"features\":[\"full\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.23.1\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"fmt\",\"json\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.16\"},{\"kind\":\"dev\",\"name\":\"tracing-test\",\"req\":\"^0.2.4\"},{\"name\":\"url\",\"req\":\"^2.5.4\"},{\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.18.1\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"allow-compilation\":[],\"behavior-version-latest\":[],\"client-hyper\":[\"aws-smithy-runtime/default-https-client\"],\"credentials-login\":[\"dep:aws-sdk-signin\",\"dep:sha2\",\"dep:zeroize\",\"dep:hex\",\"dep:base64-simd\",\"dep:uuid\",\"uuid?/v4\",\"dep:p256\",\"p256?/arithmetic\",\"p256?/pem\",\"dep:rand\"],\"credentials-process\":[\"tokio/process\"],\"default\":[\"default-https-client\",\"rt-tokio\",\"credentials-process\",\"sso\"],\"default-https-client\":[\"aws-smithy-runtime/default-https-client\"],\"rt-tokio\":[\"aws-smithy-async/rt-tokio\",\"aws-smithy-runtime/rt-tokio\",\"tokio/rt\"],\"rustls\":[\"client-hyper\"],\"sso\":[\"dep:aws-sdk-sso\",\"dep:aws-sdk-ssooidc\",\"dep:ring\",\"dep:hex\",\"dep:zeroize\",\"aws-smithy-runtime-api/http-auth\"],\"test-util\":[\"aws-runtime/test-util\"]}}", "aws-credential-types_1.2.12": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1.74\"},{\"name\":\"aws-smithy-async\",\"req\":\"^1.2.12\"},{\"features\":[\"client\",\"http-auth\"],\"name\":\"aws-smithy-runtime-api\",\"req\":\"^1.11.4\"},{\"features\":[\"test-util\"],\"kind\":\"dev\",\"name\":\"aws-smithy-runtime-api\",\"req\":\"^1.11.4\"},{\"name\":\"aws-smithy-types\",\"req\":\"^1.4.4\"},{\"features\":[\"full\",\"test-util\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.23.1\"},{\"name\":\"zeroize\",\"req\":\"^1.7.0\"}],\"features\":{\"hardcoded-credentials\":[],\"test-util\":[\"aws-smithy-runtime-api/test-util\"]}}", @@ -827,10 +723,10 @@ "axum-core_0.5.6": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1.2\"},{\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.0.0\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.25.0\"},{\"features\":[\"limit\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"limit\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.37\"}],\"features\":{\"__private_docs\":[\"dep:tower-http\"],\"tracing\":[\"dep:tracing\"]}}", "axum_0.8.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"axum-core\",\"req\":\"^0.5.5\"},{\"name\":\"axum-macros\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"form_urlencoded\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.1.0\"},{\"features\":[\"client\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\"},{\"features\":[\"tokio\",\"server\",\"service\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.3\"},{\"name\":\"itoa\",\"req\":\"^1.0.5\"},{\"name\":\"matchit\",\"req\":\"=0.8.4\"},{\"name\":\"memchr\",\"req\":\"^2.4.1\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"multer\",\"optional\":true,\"req\":\"^3.0.0\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.211\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.221\"},{\"name\":\"serde_core\",\"req\":\"^1.0.221\"},{\"features\":[\"raw_value\"],\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"raw_value\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"serde_path_to_error\",\"optional\":true,\"req\":\"^0.1.8\"},{\"name\":\"serde_urlencoded\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"serde-human-readable\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\"},{\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^1.44\"},{\"features\":[\"macros\",\"rt\",\"rt-multi-thread\",\"net\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"package\":\"tokio\",\"req\":\"^1.44.2\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"name\":\"tokio-tungstenite\",\"optional\":true,\"req\":\"^0.28.0\"},{\"kind\":\"dev\",\"name\":\"tokio-tungstenite\",\"req\":\"^0.28.0\"},{\"default_features\":false,\"features\":[\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"util\",\"timeout\",\"limit\",\"load-shed\",\"steer\",\"filter\"],\"kind\":\"dev\",\"name\":\"tower\",\"package\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.2\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"features\":[\"serde\",\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"__private\":[\"tokio\",\"http1\",\"dep:reqwest\"],\"__private_docs\":[\"axum-core/__private_docs\",\"tower/full\",\"dep:serde\",\"dep:tower-http\"],\"default\":[\"form\",\"http1\",\"json\",\"matched-path\",\"original-uri\",\"query\",\"tokio\",\"tower-log\",\"tracing\"],\"form\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"http1\":[\"dep:hyper\",\"hyper?/http1\",\"hyper-util?/http1\"],\"http2\":[\"dep:hyper\",\"hyper?/http2\",\"hyper-util?/http2\"],\"json\":[\"dep:serde_json\",\"dep:serde_path_to_error\"],\"macros\":[\"dep:axum-macros\"],\"matched-path\":[],\"multipart\":[\"dep:multer\"],\"original-uri\":[],\"query\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"tokio\":[\"dep:hyper-util\",\"dep:tokio\",\"tokio/net\",\"tokio/rt\",\"tower/make\",\"tokio/macros\"],\"tower-log\":[\"tower/log\"],\"tracing\":[\"dep:tracing\",\"axum-core/tracing\"],\"ws\":[\"dep:hyper\",\"tokio\",\"dep:tokio-tungstenite\",\"dep:sha1\",\"dep:base64\"]}}", "axum_0.8.8": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"axum-core\",\"req\":\"^0.5.5\"},{\"name\":\"axum-macros\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"form_urlencoded\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.1.0\"},{\"features\":[\"client\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\"},{\"features\":[\"tokio\",\"server\",\"service\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.3\"},{\"name\":\"itoa\",\"req\":\"^1.0.5\"},{\"name\":\"matchit\",\"req\":\"=0.8.4\"},{\"name\":\"memchr\",\"req\":\"^2.4.1\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"multer\",\"optional\":true,\"req\":\"^3.0.0\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.211\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.221\"},{\"name\":\"serde_core\",\"req\":\"^1.0.221\"},{\"features\":[\"raw_value\"],\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"raw_value\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"serde_path_to_error\",\"optional\":true,\"req\":\"^0.1.8\"},{\"name\":\"serde_urlencoded\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"serde-human-readable\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\"},{\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^1.44\"},{\"features\":[\"macros\",\"rt\",\"rt-multi-thread\",\"net\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"package\":\"tokio\",\"req\":\"^1.44.2\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"name\":\"tokio-tungstenite\",\"optional\":true,\"req\":\"^0.28.0\"},{\"kind\":\"dev\",\"name\":\"tokio-tungstenite\",\"req\":\"^0.28.0\"},{\"default_features\":false,\"features\":[\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"util\",\"timeout\",\"limit\",\"load-shed\",\"steer\",\"filter\"],\"kind\":\"dev\",\"name\":\"tower\",\"package\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.2\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"features\":[\"serde\",\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"__private\":[\"tokio\",\"http1\",\"dep:reqwest\"],\"__private_docs\":[\"axum-core/__private_docs\",\"tower/full\",\"dep:serde\",\"dep:tower-http\"],\"default\":[\"form\",\"http1\",\"json\",\"matched-path\",\"original-uri\",\"query\",\"tokio\",\"tower-log\",\"tracing\"],\"form\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"http1\":[\"dep:hyper\",\"hyper?/http1\",\"hyper-util?/http1\"],\"http2\":[\"dep:hyper\",\"hyper?/http2\",\"hyper-util?/http2\"],\"json\":[\"dep:serde_json\",\"dep:serde_path_to_error\"],\"macros\":[\"dep:axum-macros\"],\"matched-path\":[],\"multipart\":[\"dep:multer\"],\"original-uri\":[],\"query\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"tokio\":[\"dep:hyper-util\",\"dep:tokio\",\"tokio/net\",\"tokio/rt\",\"tower/make\",\"tokio/macros\"],\"tower-log\":[\"tower/log\"],\"tracing\":[\"dep:tracing\",\"axum-core/tracing\"],\"ws\":[\"dep:hyper\",\"tokio\",\"dep:tokio-tungstenite\",\"dep:sha1\",\"dep:base64\"]}}", - "azure_core_0.21.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"dyn-clone\",\"req\":\"^1.0\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"features\":[\"js\"],\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"name\":\"http-types\",\"req\":\"^2.12\"},{\"name\":\"once_cell\",\"req\":\"^1.18\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"paste\",\"req\":\"^1.0\"},{\"name\":\"pin-project\",\"req\":\"^1.0\"},{\"features\":[\"serialize\",\"serde-types\"],\"name\":\"quick-xml\",\"optional\":true,\"req\":\"^0.31\"},{\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"stream\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12.0\"},{\"kind\":\"build\",\"name\":\"rustc_version\",\"req\":\"^0.4\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^1.0\"},{\"features\":[\"serde-well-known\",\"macros\"],\"name\":\"time\",\"req\":\"^0.3.10\"},{\"features\":[\"wasm-bindgen\"],\"name\":\"time\",\"req\":\"^0.3.10\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"default\",\"macros\",\"rt\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"name\":\"tracing\",\"req\":\"^0.1.40\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"req\":\"^2.2\"},{\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"azurite_workaround\":[],\"default\":[],\"enable_reqwest\":[\"reqwest/default-tls\"],\"enable_reqwest_gzip\":[\"reqwest/gzip\"],\"enable_reqwest_rustls\":[\"reqwest/rustls-tls\"],\"hmac_openssl\":[\"dep:openssl\"],\"hmac_rust\":[\"dep:sha2\",\"dep:hmac\"],\"test_e2e\":[],\"tokio-fs\":[\"tokio/fs\",\"tokio/sync\",\"tokio/io-util\"],\"tokio-sleep\":[\"tokio\"],\"xml\":[\"quick-xml\"]}}", - "azure_storage_0.21.0": "{\"dependencies\":[{\"name\":\"RustyXML\",\"req\":\"^0.3\"},{\"name\":\"async-lock\",\"req\":\"^3.1\"},{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"features\":[\"xml\"],\"name\":\"azure_core\",\"req\":\"^0.21\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"name\":\"time\",\"req\":\"^0.3.10\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"name\":\"tracing\",\"req\":\"^0.1.40\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"req\":\"^2.2\"},{\"features\":[\"v4\",\"serde\"],\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"enable_reqwest\",\"hmac_rust\"],\"enable_reqwest\":[\"azure_core/enable_reqwest\"],\"enable_reqwest_rustls\":[\"azure_core/enable_reqwest_rustls\"],\"hmac_openssl\":[\"azure_core/hmac_openssl\"],\"hmac_rust\":[\"azure_core/hmac_rust\"],\"test_e2e\":[],\"test_integration\":[]}}", - "azure_storage_blobs_0.21.0": "{\"dependencies\":[{\"name\":\"RustyXML\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"features\":[\"xml\"],\"name\":\"azure_core\",\"req\":\"^0.21\"},{\"features\":[\"tokio-fs\"],\"kind\":\"dev\",\"name\":\"azure_core\",\"req\":\"^0.21\"},{\"default_features\":false,\"name\":\"azure_storage\",\"req\":\"^0.21\"},{\"default_features\":false,\"features\":[\"default_tag\"],\"name\":\"azure_svc_blobstorage\",\"req\":\"^0.21\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"features\":[\"derive\",\"env\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.0\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"md5\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"md5\",\"req\":\"^0.7\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"time\",\"req\":\"^0.3.10\"},{\"features\":[\"macros\",\"rt-multi-thread\",\"io-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"name\":\"tracing\",\"req\":\"^0.1.40\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"req\":\"^2.2\"},{\"features\":[\"v4\",\"serde\"],\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"azurite_workaround\":[\"azure_core/azurite_workaround\"],\"default\":[\"enable_reqwest\",\"hmac_rust\"],\"enable_reqwest\":[\"azure_core/enable_reqwest\",\"azure_storage/enable_reqwest\",\"azure_svc_blobstorage/enable_reqwest\"],\"enable_reqwest_rustls\":[\"azure_core/enable_reqwest_rustls\",\"azure_storage/enable_reqwest_rustls\",\"azure_svc_blobstorage/enable_reqwest_rustls\"],\"hmac_openssl\":[\"azure_core/hmac_openssl\"],\"hmac_rust\":[\"azure_core/hmac_rust\"],\"md5\":[\"dep:md5\"],\"test_e2e\":[],\"test_integration\":[]}}", - "azure_svc_blobstorage_0.21.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"features\":[\"xml\"],\"name\":\"azure_core\",\"req\":\"^0.21\"},{\"name\":\"bytes\",\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"req\":\"^1.18\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"time\",\"req\":\"^0.3\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.23\"}],\"features\":{\"default\":[\"default_tag\",\"enable_reqwest\"],\"default_tag\":[\"package-2021-12\"],\"enable_reqwest\":[\"azure_core/enable_reqwest\"],\"enable_reqwest_rustls\":[\"azure_core/enable_reqwest_rustls\"],\"package-2021-02\":[],\"package-2021-04\":[],\"package-2021-08\":[],\"package-2021-12\":[],\"package-2021-12-preview\":[]}}", + "azure_core_1.0.0": "{\"dependencies\":[{\"name\":\"async-lock\",\"req\":\"^3.4\"},{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"azure_core_macros\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"azure_core_macros\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1.11.1\"},{\"features\":[\"async_tokio\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"include-file\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"json-patch\",\"req\":\"^4.1.0\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.79\"},{\"name\":\"pin-project\",\"req\":\"^1.1\"},{\"default_features\":false,\"features\":[\"stream\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.13.2\"},{\"kind\":\"build\",\"name\":\"rustc_version\",\"req\":\"^0.4\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0.149\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"macros\",\"time\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.49\"},{\"default_features\":false,\"features\":[\"macros\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.49\"},{\"name\":\"tracing\",\"req\":\"^0.1.44\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"http\",\"json\"],\"name\":\"typespec\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"derive\",\"http\",\"json\"],\"name\":\"typespec_client_core\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"gzip\",\"native-tls\"],\"kind\":\"dev\",\"name\":\"ureq\",\"req\":\"^3.2.0\"}],\"features\":{\"debug\":[\"typespec_client_core/debug\"],\"decimal\":[\"typespec_client_core/decimal\"],\"default\":[\"reqwest\",\"reqwest_deflate\",\"reqwest_gzip\",\"reqwest_rustls\",\"tokio\"],\"hmac_openssl\":[\"dep:openssl\"],\"hmac_rust\":[\"dep:sha2\",\"dep:hmac\"],\"reqwest\":[\"typespec_client_core/reqwest\"],\"reqwest_deflate\":[\"reqwest\",\"typespec_client_core/reqwest_deflate\"],\"reqwest_gzip\":[\"reqwest\",\"typespec_client_core/reqwest_gzip\"],\"reqwest_rustls\":[\"reqwest\",\"typespec_client_core/reqwest_rustls\"],\"test\":[\"typespec_client_core/test\"],\"tokio\":[\"dep:tokio\",\"typespec_client_core/tokio\"],\"xml\":[\"typespec_client_core/xml\"]}}", + "azure_core_macros_1.0.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.115\"},{\"default_features\":false,\"features\":[\"macros\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.49\"},{\"name\":\"tracing\",\"req\":\"^0.1.44\"},{\"features\":[\"env-filter\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"}],\"features\":{}}", + "azure_identity_1.0.0": "{\"dependencies\":[{\"name\":\"async-lock\",\"req\":\"^3.4\"},{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"azure_core\",\"req\":\"^1.0.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.5.58\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"include-file\",\"req\":\"^0.5.1\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.79\"},{\"name\":\"pin-project\",\"req\":\"^1.1\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0.149\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.149\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.3\"},{\"features\":[\"serde-well-known\",\"macros\"],\"name\":\"time\",\"req\":\"^0.3.47\"},{\"default_features\":false,\"features\":[\"macros\",\"time\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.49\"},{\"default_features\":false,\"features\":[\"macros\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.49\"},{\"name\":\"tracing\",\"req\":\"^0.1.44\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"req\":\"^2.5\"}],\"features\":{\"client_certificate\":[\"openssl\"],\"default\":[\"azure_core/default\"],\"tokio\":[\"dep:tokio\",\"azure_core/tokio\",\"tokio/process\"]}}", + "azure_storage_blob_1.0.0": "{\"dependencies\":[{\"name\":\"async-stream\",\"req\":\"^0.3.6\"},{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"xml\"],\"name\":\"azure_core\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1.11.1\"},{\"features\":[\"derive\",\"env\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.5.58\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.1.9\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"features\":[\"trace\"],\"kind\":\"dev\",\"name\":\"opentelemetry\",\"req\":\"^0.31\"},{\"kind\":\"dev\",\"name\":\"opentelemetry-stdout\",\"req\":\"^0.31\"},{\"kind\":\"dev\",\"name\":\"opentelemetry_sdk\",\"req\":\"^0.31\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"name\":\"pin-project\",\"req\":\"^1.1\"},{\"features\":[\"sys_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10.1\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0.149\"},{\"features\":[\"serde-well-known\",\"macros\"],\"name\":\"time\",\"req\":\"^0.3.47\"},{\"default_features\":false,\"features\":[\"macros\",\"time\",\"fs\",\"io-util\",\"sync\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.49\"},{\"default_features\":false,\"features\":[\"macros\",\"time\",\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.49\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.44\"},{\"features\":[\"env-filter\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"}],\"features\":{\"default\":[\"tokio\",\"azure_core/default\"],\"tokio\":[\"dep:tokio\",\"azure_core/tokio\"]}}", "backon_1.6.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"name\":\"embassy-time\",\"optional\":true,\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"fastrand\",\"req\":\"^2\"},{\"name\":\"futures-timer\",\"optional\":true,\"req\":\"^3.0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"gloo-timers\"],\"name\":\"futures-timer\",\"optional\":true,\"req\":\"^3.0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"gloo-timers\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"spin\",\"req\":\"^0.10.0\"},{\"features\":[\"runtime-tokio\",\"sqlite\"],\"kind\":\"dev\",\"name\":\"sqlx\",\"req\":\"^0.8.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"macros\",\"rt\",\"sync\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"features\":[\"time\",\"rt\",\"macros\",\"sync\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"}],\"features\":{\"default\":[\"std\",\"std-blocking-sleep\",\"tokio-sleep\",\"gloo-timers-sleep\"],\"embassy-sleep\":[\"embassy-time\"],\"futures-timer-sleep\":[\"futures-timer\"],\"gloo-timers-sleep\":[\"gloo-timers/futures\"],\"std\":[\"fastrand/std\"],\"std-blocking-sleep\":[],\"tokio-sleep\":[\"tokio/time\"]}}", "base16ct_0.2.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"std\":[\"alloc\"]}}", "base64-simd_0.8.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.20.0\"},{\"kind\":\"dev\",\"name\":\"const-str\",\"req\":\"^0.5.3\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.8\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"outref\",\"req\":\"^0.5.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"name\":\"vsimd\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.33\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"}],\"features\":{\"alloc\":[\"vsimd/alloc\"],\"default\":[\"std\",\"detect\"],\"detect\":[\"vsimd/detect\"],\"std\":[\"alloc\",\"vsimd/std\"],\"unstable\":[\"vsimd/unstable\"]}}", @@ -843,8 +739,11 @@ "bitvec_1.0.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"funty\",\"req\":\"^2.0\"},{\"name\":\"radium\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"},{\"name\":\"tap\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"wyz\",\"req\":\"^0.5\"}],\"features\":{\"alloc\":[],\"atomic\":[],\"default\":[\"atomic\",\"std\"],\"std\":[\"alloc\"],\"testing\":[]}}", "blake3_1.8.2": "{\"dependencies\":[{\"name\":\"arrayref\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"name\":\"arrayvec\",\"req\":\"^0.7.4\"},{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.1.12\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"ciborium\",\"req\":\"^0.2.2\"},{\"default_features\":false,\"name\":\"constant_time_eq\",\"req\":\"^0.3.1\"},{\"features\":[\"mac\"],\"name\":\"digest\",\"optional\":true,\"req\":\"^0.10.1\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.2\"},{\"kind\":\"dev\",\"name\":\"hmac\",\"req\":\"^0.12.0\"},{\"name\":\"memmap2\",\"optional\":true,\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"page_size\",\"req\":\"^0.6.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand_chacha\",\"req\":\"^0.9.0\"},{\"name\":\"rayon-core\",\"optional\":true,\"req\":\"^1.12.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.107\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.8.0\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"digest\":[\"dep:digest\"],\"mmap\":[\"std\",\"dep:memmap2\"],\"neon\":[],\"no_avx2\":[],\"no_avx512\":[],\"no_neon\":[],\"no_sse2\":[],\"no_sse41\":[],\"prefer_intrinsics\":[],\"pure\":[],\"rayon\":[\"dep:rayon-core\"],\"std\":[],\"traits-preview\":[\"dep:digest\"],\"wasm32_simd\":[],\"zeroize\":[\"dep:zeroize\",\"arrayvec/zeroize\"]}}", "block-buffer_0.10.4": "{\"dependencies\":[{\"name\":\"generic-array\",\"req\":\"^0.14\"}],\"features\":{}}", + "brotli-decompressor_4.0.3": "{\"dependencies\":[{\"name\":\"alloc-no-stdlib\",\"req\":\"~2.0\"},{\"name\":\"alloc-stdlib\",\"optional\":true,\"req\":\"~0.2\"}],\"features\":{\"benchmark\":[],\"default\":[\"std\"],\"disable-timer\":[],\"ffi-api\":[],\"pass-through-ffi-panics\":[],\"seccomp\":[],\"std\":[\"alloc-stdlib\"],\"unsafe\":[\"alloc-no-stdlib/unsafe\",\"alloc-stdlib/unsafe\"]}}", "bs58_0.5.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.3.0\"},{\"kind\":\"dev\",\"name\":\"base58\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"rust-base58\",\"req\":\"^0.0.4\"},{\"default_features\":false,\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"grab_spare_slice\"],\"name\":\"tinyvec\",\"optional\":true,\"req\":\"^1.6.0\"},{\"features\":[\"rustc_1_55\"],\"kind\":\"dev\",\"name\":\"tinyvec\",\"req\":\"^1.6.0\"}],\"features\":{\"alloc\":[\"tinyvec?/alloc\"],\"cb58\":[\"sha2\"],\"check\":[\"sha2\"],\"default\":[\"std\"],\"std\":[\"alloc\",\"tinyvec?/std\"]}}", "bson_2.15.0": "{\"dependencies\":[{\"name\":\"ahash\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.2\"},{\"name\":\"base64\",\"req\":\"^0.22.1\"},{\"name\":\"bitvec\",\"req\":\"^1.0.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.15\"},{\"default_features\":false,\"features\":[\"serde\",\"clock\",\"std\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.0\"},{\"features\":[\"js\"],\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"wasm_js\"],\"name\":\"getrandom_03\",\"package\":\"getrandom\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"hex\",\"req\":\"^0.4.2\"},{\"name\":\"indexmap\",\"req\":\"^2.1.0\"},{\"name\":\"js-sys\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"once_cell\",\"req\":\"^1.5.1\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.6.1\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0.0\"},{\"name\":\"rand\",\"req\":\"^0.9\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_bytes\",\"req\":\"^0.11.5\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11\"},{\"features\":[\"preserve_order\"],\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"serde_path_to_error\",\"optional\":true,\"req\":\"^0.1.16\"},{\"kind\":\"dev\",\"name\":\"serde_path_to_error\",\"req\":\"^0.1.16\"},{\"name\":\"serde_with\",\"optional\":true,\"req\":\"^1.3.1\"},{\"name\":\"serde_with-3\",\"optional\":true,\"package\":\"serde_with\",\"req\":\"^3.1.0\"},{\"features\":[\"formatting\",\"parsing\",\"macros\",\"large-dates\"],\"name\":\"time\",\"req\":\"^0.3.9\"},{\"features\":[\"serde\",\"v4\"],\"name\":\"uuid\",\"req\":\"^1.1.2\"},{\"features\":[\"serde\",\"v4\",\"js\"],\"name\":\"uuid\",\"req\":\"^1.1.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"serde\",\"v4\"],\"name\":\"uuid-0_8\",\"optional\":true,\"package\":\"uuid\",\"req\":\"^0.8.1\"}],\"features\":{\"chrono-0_4\":[\"chrono\"],\"default\":[],\"hashable\":[],\"serde_path_to_error\":[\"dep:serde_path_to_error\"],\"time-0_3\":[],\"uncapped_max_size\":[],\"uuid-1\":[]}}", + "buf_redux_0.8.4": "{\"dependencies\":[{\"name\":\"memchr\",\"req\":\"^2.0\"},{\"name\":\"safemem\",\"req\":\"^0.3\"},{\"name\":\"slice-deque\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(any(unix, windows))\"}],\"features\":{\"default\":[\"slice-deque\"],\"nightly\":[\"slice-deque/unstable\"]}}", + "bumpalo_3.20.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.8\"},{\"kind\":\"dev\",\"name\":\"blink-alloc\",\"req\":\"=0.4.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"=1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"=1.10.0\"},{\"kind\":\"dev\",\"name\":\"rayon-core\",\"req\":\"=1.12.1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.171\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.197\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.115\"}],\"features\":{\"allocator_api\":[],\"bench_allocator_api\":[\"allocator_api\",\"blink-alloc/nightly\"],\"boxed\":[],\"collections\":[],\"default\":[],\"serde\":[\"dep:serde\"],\"std\":[]}}", "bumpalo_3.20.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.8\"},{\"kind\":\"dev\",\"name\":\"blink-alloc\",\"req\":\"=0.4.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"=1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"=1.10.0\"},{\"kind\":\"dev\",\"name\":\"rayon-core\",\"req\":\"=1.12.1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.171\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.197\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.115\"}],\"features\":{\"allocator_api\":[],\"bench_allocator_api\":[\"allocator_api\",\"blink-alloc/nightly\"],\"boxed\":[],\"collections\":[],\"default\":[],\"serde\":[\"dep:serde\"],\"std\":[]}}", "byte-unit_5.1.6": "{\"dependencies\":[{\"name\":\"rocket\",\"optional\":true,\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"rust_decimal\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"utf8-width\",\"req\":\"^0.1\"}],\"features\":{\"bit\":[\"rust_decimal\"],\"byte\":[\"rust_decimal\"],\"default\":[\"std\",\"byte\"],\"rocket\":[\"dep:rocket\",\"std\"],\"rust_decimal\":[\"dep:rust_decimal\"],\"serde\":[\"dep:serde\"],\"std\":[\"serde?/std\",\"rust_decimal?/std\"],\"u128\":[]}}", "bytemuck_1.25.0": "{\"dependencies\":[{\"name\":\"bytemuck_derive\",\"optional\":true,\"req\":\"^1.10.2\"},{\"name\":\"rustversion\",\"optional\":true,\"req\":\"^1.0.22\"}],\"features\":{\"aarch64_simd\":[],\"align_offset\":[],\"alloc_uninit\":[],\"avx512_simd\":[],\"const_zeroed\":[],\"derive\":[\"bytemuck_derive\"],\"extern_crate_alloc\":[],\"extern_crate_std\":[\"extern_crate_alloc\"],\"impl_core_error\":[],\"latest_stable_rust\":[\"aarch64_simd\",\"avx512_simd\",\"align_offset\",\"alloc_uninit\",\"const_zeroed\",\"derive\",\"impl_core_error\",\"min_const_generics\",\"must_cast\",\"must_cast_extra\",\"pod_saturating\",\"track_caller\",\"transparentwrapper_extra\",\"wasm_simd\",\"zeroable_atomics\",\"zeroable_maybe_uninit\",\"zeroable_unwind_fn\"],\"min_const_generics\":[],\"must_cast\":[],\"must_cast_extra\":[\"must_cast\"],\"nightly_docs\":[],\"nightly_float\":[],\"nightly_portable_simd\":[\"rustversion\"],\"nightly_stdsimd\":[],\"pod_saturating\":[],\"track_caller\":[],\"transparentwrapper_extra\":[],\"unsound_ptr_pod_impl\":[],\"wasm_simd\":[],\"zeroable_atomics\":[],\"zeroable_maybe_uninit\":[],\"zeroable_unwind_fn\":[]}}", @@ -853,21 +752,24 @@ "bytes_1.11.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"extra-platforms\",\"optional\":true,\"package\":\"portable-atomic\",\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.60\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "camino_1.2.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"name\":\"proptest\",\"optional\":true,\"req\":\"^1.0.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.223\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.8\"},{\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"proptest1\":[\"dep:proptest\"],\"serde1\":[\"dep:serde_core\"]}}", "cbor-diag_0.1.12": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"bs58\",\"req\":\"^0.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"chrono\",\"req\":\"^0.4.22\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"data-encoding\",\"req\":\"^2.3.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"data-encoding-macro\",\"req\":\"^0.1.12\"},{\"default_features\":false,\"name\":\"half\",\"req\":\"^2.1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2.0.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"nom\",\"req\":\"^7.1.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"num-bigint\",\"req\":\"^0.4.3\"},{\"default_features\":false,\"features\":[\"num-bigint\"],\"name\":\"num-rational\",\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2.15\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.3.0\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"separator\",\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"url\",\"req\":\"^2.3.1\"},{\"default_features\":false,\"name\":\"uuid\",\"req\":\"^1.1.2\"}],\"features\":{}}", + "cc_1.2.62": "{\"dependencies\":[{\"name\":\"find-msvc-tools\",\"req\":\"^0.1.9\"},{\"default_features\":false,\"name\":\"jobserver\",\"optional\":true,\"req\":\"^0.1.30\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.62\",\"target\":\"cfg(unix)\"},{\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"jobserver\":[],\"parallel\":[\"dep:libc\",\"dep:jobserver\"]}}", "cc_1.2.63": "{\"dependencies\":[{\"name\":\"find-msvc-tools\",\"req\":\"^0.1.9\"},{\"default_features\":false,\"name\":\"jobserver\",\"optional\":true,\"req\":\"^0.1.30\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.62\",\"target\":\"cfg(unix)\"},{\"name\":\"shlex\",\"req\":\"^2.0.1\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"jobserver\":[],\"parallel\":[\"dep:libc\",\"dep:jobserver\"]}}", "cesu8_1.1.0": "{\"dependencies\":[],\"features\":{\"unstable\":[]}}", "cfg-if_1.0.4": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"rustc-dep-of-std\":[\"core\"]}}", - "cfg_aliases_0.2.1": "{\"dependencies\":[],\"features\":{}}", "chacha20_0.10.0": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"features\":[\"stream-wrapper\"],\"name\":\"cipher\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"cipher\",\"req\":\"^0.5\"},{\"name\":\"cpufeatures\",\"req\":\"^0.3\",\"target\":\"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.8.1\"}],\"features\":{\"default\":[\"cipher\"],\"legacy\":[\"cipher\"],\"rng\":[\"dep:rand_core\"],\"xchacha\":[\"cipher\"]}}", "chrono_0.4.44": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.0\"},{\"name\":\"defmt\",\"optional\":true,\"req\":\"^1.0.1\"},{\"features\":[\"fallback\"],\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1.45\",\"target\":\"cfg(unix)\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"name\":\"pure-rust-locales\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.43\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.99\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"similar-asserts\",\"req\":\"^1.6.1\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"windows-bindgen\",\"req\":\"^0.66\"},{\"name\":\"windows-link\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(windows)\"}],\"features\":{\"__internal_bench\":[],\"alloc\":[],\"clock\":[\"winapi\",\"iana-time-zone\",\"now\"],\"core-error\":[],\"default\":[\"clock\",\"std\",\"oldtime\",\"wasmbind\"],\"defmt\":[\"dep:defmt\",\"pure-rust-locales?/defmt\"],\"libc\":[],\"now\":[\"std\"],\"oldtime\":[],\"rkyv\":[\"dep:rkyv\",\"rkyv/size_32\"],\"rkyv-16\":[\"dep:rkyv\",\"rkyv?/size_16\"],\"rkyv-32\":[\"dep:rkyv\",\"rkyv?/size_32\"],\"rkyv-64\":[\"dep:rkyv\",\"rkyv?/size_64\"],\"rkyv-validation\":[\"rkyv?/validation\"],\"std\":[\"alloc\"],\"unstable-locales\":[\"pure-rust-locales\"],\"wasmbind\":[\"wasm-bindgen\",\"js-sys\"],\"winapi\":[\"windows-link\"]}}", + "chunked_transfer_1.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"}],\"features\":{}}", "ciborium-io_0.2.2": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"std\":[\"alloc\"]}}", "ciborium-ll_0.2.2": "{\"dependencies\":[{\"name\":\"ciborium-io\",\"req\":\"^0.2.2\"},{\"default_features\":false,\"name\":\"half\",\"req\":\"^2.2\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"}],\"features\":{\"alloc\":[],\"std\":[\"alloc\",\"half/std\"]}}", "ciborium_0.2.2": "{\"dependencies\":[{\"features\":[\"alloc\"],\"name\":\"ciborium-io\",\"req\":\"^0.2.2\"},{\"name\":\"ciborium-ll\",\"req\":\"^0.2.2\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"alloc\",\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.100\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"ciborium-io/std\",\"serde/std\"]}}", "clap_4.5.50": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.14\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"clap-cargo\",\"req\":\"^0.15.0\"},{\"default_features\":false,\"name\":\"clap_builder\",\"req\":\"=4.5.50\"},{\"name\":\"clap_derive\",\"optional\":true,\"req\":\"=4.5.49\"},{\"kind\":\"dev\",\"name\":\"jiff\",\"req\":\"^0.2.3\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.15\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.26\"},{\"kind\":\"dev\",\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"features\":[\"term-svg\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.16\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.91\"},{\"default_features\":false,\"features\":[\"color-auto\",\"diff\",\"examples\"],\"kind\":\"dev\",\"name\":\"trycmd\",\"req\":\"^0.15.3\"}],\"features\":{\"cargo\":[\"clap_builder/cargo\"],\"color\":[\"clap_builder/color\"],\"debug\":[\"clap_builder/debug\",\"clap_derive?/debug\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[\"clap_builder/deprecated\",\"clap_derive?/deprecated\"],\"derive\":[\"dep:clap_derive\"],\"env\":[\"clap_builder/env\"],\"error-context\":[\"clap_builder/error-context\"],\"help\":[\"clap_builder/help\"],\"std\":[\"clap_builder/std\"],\"string\":[\"clap_builder/string\"],\"suggestions\":[\"clap_builder/suggestions\"],\"unicode\":[\"clap_builder/unicode\"],\"unstable-derive-ui-tests\":[],\"unstable-doc\":[\"clap_builder/unstable-doc\",\"derive\"],\"unstable-ext\":[\"clap_builder/unstable-ext\"],\"unstable-markdown\":[\"clap_derive/unstable-markdown\"],\"unstable-styles\":[\"clap_builder/unstable-styles\"],\"unstable-v5\":[\"clap_builder/unstable-v5\",\"clap_derive?/unstable-v5\",\"deprecated\"],\"usage\":[\"clap_builder/usage\"],\"wrap_help\":[\"clap_builder/wrap_help\"]}}", "clap_4.6.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"clap-cargo\",\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"clap_builder\",\"req\":\"=4.6.0\"},{\"name\":\"clap_derive\",\"optional\":true,\"req\":\"=4.6.0\"},{\"kind\":\"dev\",\"name\":\"jiff\",\"req\":\"^0.2.23\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.27\"},{\"kind\":\"dev\",\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"features\":[\"term-svg\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.116\"},{\"default_features\":false,\"features\":[\"color-auto\",\"diff\",\"examples\"],\"kind\":\"dev\",\"name\":\"trycmd\",\"req\":\"^1.1.1\"}],\"features\":{\"cargo\":[\"clap_builder/cargo\"],\"color\":[\"clap_builder/color\"],\"debug\":[\"clap_builder/debug\",\"clap_derive?/debug\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[\"clap_builder/deprecated\",\"clap_derive?/deprecated\"],\"derive\":[\"dep:clap_derive\"],\"env\":[\"clap_builder/env\"],\"error-context\":[\"clap_builder/error-context\"],\"help\":[\"clap_builder/help\"],\"std\":[\"clap_builder/std\"],\"string\":[\"clap_builder/string\"],\"suggestions\":[\"clap_builder/suggestions\"],\"unicode\":[\"clap_builder/unicode\"],\"unstable-derive-ui-tests\":[],\"unstable-doc\":[\"clap_builder/unstable-doc\",\"derive\"],\"unstable-ext\":[\"clap_builder/unstable-ext\"],\"unstable-markdown\":[\"clap_derive/unstable-markdown\"],\"unstable-styles\":[\"clap_builder/unstable-styles\"],\"unstable-v5\":[\"clap_builder/unstable-v5\",\"clap_derive?/unstable-v5\",\"deprecated\"],\"usage\":[\"clap_builder/usage\"],\"wrap_help\":[\"clap_builder/wrap_help\"]}}", + "clap_4.6.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"clap-cargo\",\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"clap_builder\",\"req\":\"=4.6.0\"},{\"name\":\"clap_derive\",\"optional\":true,\"req\":\"=4.6.1\"},{\"kind\":\"dev\",\"name\":\"jiff\",\"req\":\"^0.2.23\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.27\"},{\"kind\":\"dev\",\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"features\":[\"term-svg\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.116\"},{\"default_features\":false,\"features\":[\"color-auto\",\"diff\",\"examples\"],\"kind\":\"dev\",\"name\":\"trycmd\",\"req\":\"^1.2.0\"}],\"features\":{\"cargo\":[\"clap_builder/cargo\"],\"color\":[\"clap_builder/color\"],\"debug\":[\"clap_builder/debug\",\"clap_derive?/debug\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[\"clap_builder/deprecated\",\"clap_derive?/deprecated\"],\"derive\":[\"dep:clap_derive\"],\"env\":[\"clap_builder/env\"],\"error-context\":[\"clap_builder/error-context\"],\"help\":[\"clap_builder/help\"],\"std\":[\"clap_builder/std\"],\"string\":[\"clap_builder/string\"],\"suggestions\":[\"clap_builder/suggestions\"],\"unicode\":[\"clap_builder/unicode\"],\"unstable-derive-ui-tests\":[],\"unstable-doc\":[\"clap_builder/unstable-doc\",\"derive\"],\"unstable-ext\":[\"clap_builder/unstable-ext\"],\"unstable-markdown\":[\"clap_derive/unstable-markdown\"],\"unstable-styles\":[\"clap_builder/unstable-styles\"],\"unstable-v5\":[\"clap_builder/unstable-v5\",\"clap_derive?/unstable-v5\",\"deprecated\"],\"usage\":[\"clap_builder/usage\"],\"wrap_help\":[\"clap_builder/wrap_help\"]}}", "clap_builder_4.5.50": "{\"dependencies\":[{\"name\":\"anstream\",\"optional\":true,\"req\":\"^0.6.7\"},{\"name\":\"anstyle\",\"req\":\"^1.0.8\"},{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.73\"},{\"name\":\"clap_lex\",\"req\":\"^0.7.4\"},{\"kind\":\"dev\",\"name\":\"color-print\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.16\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"name\":\"strsim\",\"optional\":true,\"req\":\"^0.11.0\"},{\"name\":\"terminal_size\",\"optional\":true,\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"unic-emoji-char\",\"req\":\"^0.9.0\"},{\"name\":\"unicase\",\"optional\":true,\"req\":\"^2.6.0\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2.0\"}],\"features\":{\"cargo\":[],\"color\":[\"dep:anstream\"],\"debug\":[\"dep:backtrace\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[],\"env\":[],\"error-context\":[],\"help\":[],\"std\":[\"anstyle/std\"],\"string\":[],\"suggestions\":[\"dep:strsim\",\"error-context\"],\"unicode\":[\"dep:unicode-width\",\"dep:unicase\"],\"unstable-doc\":[\"cargo\",\"wrap_help\",\"env\",\"unicode\",\"string\",\"unstable-ext\"],\"unstable-ext\":[],\"unstable-styles\":[\"color\"],\"unstable-v5\":[\"deprecated\"],\"usage\":[],\"wrap_help\":[\"help\",\"dep:terminal_size\"]}}", "clap_builder_4.6.0": "{\"dependencies\":[{\"name\":\"anstream\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"anstyle\",\"req\":\"^1.0.13\"},{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.76\"},{\"name\":\"clap_lex\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"color-print\",\"req\":\"^0.3.7\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"name\":\"strsim\",\"optional\":true,\"req\":\"^0.11.1\"},{\"name\":\"terminal_size\",\"optional\":true,\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"unic-emoji-char\",\"req\":\"^0.9.0\"},{\"name\":\"unicase\",\"optional\":true,\"req\":\"^2.9.0\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2.2\"}],\"features\":{\"cargo\":[],\"color\":[\"dep:anstream\"],\"debug\":[\"dep:backtrace\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[],\"env\":[],\"error-context\":[],\"help\":[],\"std\":[\"anstyle/std\"],\"string\":[],\"suggestions\":[\"dep:strsim\",\"error-context\"],\"unicode\":[\"dep:unicode-width\",\"dep:unicase\"],\"unstable-doc\":[\"cargo\",\"wrap_help\",\"env\",\"unicode\",\"string\",\"unstable-ext\"],\"unstable-ext\":[],\"unstable-styles\":[\"color\"],\"unstable-v5\":[\"deprecated\"],\"usage\":[],\"wrap_help\":[\"help\",\"dep:terminal_size\"]}}", "clap_derive_4.5.49": "{\"dependencies\":[{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1.0.10\"},{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.69\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13.0\"},{\"name\":\"quote\",\"req\":\"^1.0.9\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.8\"}],\"features\":{\"debug\":[],\"default\":[],\"deprecated\":[],\"raw-deprecated\":[\"deprecated\"],\"unstable-markdown\":[\"dep:pulldown-cmark\",\"dep:anstyle\"],\"unstable-v5\":[\"deprecated\"]}}", "clap_derive_4.6.0": "{\"dependencies\":[{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1.0.13\"},{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13.1\"},{\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.117\"}],\"features\":{\"debug\":[],\"default\":[],\"deprecated\":[],\"raw-deprecated\":[\"deprecated\"],\"unstable-markdown\":[\"dep:pulldown-cmark\",\"dep:anstyle\"],\"unstable-v5\":[\"deprecated\"]}}", + "clap_derive_4.6.1": "{\"dependencies\":[{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1.0.14\"},{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13.3\"},{\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.117\"}],\"features\":{\"debug\":[],\"default\":[],\"deprecated\":[],\"raw-deprecated\":[\"deprecated\"],\"unstable-markdown\":[\"dep:pulldown-cmark\",\"dep:anstyle\"],\"unstable-v5\":[\"deprecated\"]}}", "clap_lex_0.7.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.14\"}],\"features\":{}}", "clap_lex_1.1.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"}],\"features\":{}}", "colorchoice_1.0.4": "{\"dependencies\":[],\"features\":{}}", @@ -894,16 +796,18 @@ "crc_3.3.0": "{\"dependencies\":[{\"name\":\"crc-catalog\",\"req\":\"^2.4.0\"}],\"features\":{}}", "critical-section_1.2.0": "{\"dependencies\":[],\"features\":{\"restore-state-bool\":[],\"restore-state-none\":[],\"restore-state-u16\":[],\"restore-state-u32\":[],\"restore-state-u64\":[],\"restore-state-u8\":[],\"restore-state-usize\":[],\"std\":[\"restore-state-bool\"]}}", "crossbeam-channel_0.5.15": "{\"dependencies\":[{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.18\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"signal-hook\",\"req\":\"^0.3\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"crossbeam-utils/std\"]}}", + "crossbeam-deque_0.8.6": "{\"dependencies\":[{\"default_features\":false,\"name\":\"crossbeam-epoch\",\"req\":\"^0.9.17\"},{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.18\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"crossbeam-epoch/std\",\"crossbeam-utils/std\"]}}", "crossbeam-epoch_0.9.18": "{\"dependencies\":[{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.18\"},{\"name\":\"loom-crate\",\"optional\":true,\"package\":\"loom\",\"req\":\"^0.7.1\",\"target\":\"cfg(crossbeam_loom)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"loom\":[\"loom-crate\",\"crossbeam-utils/loom\"],\"nightly\":[\"crossbeam-utils/nightly\"],\"std\":[\"alloc\",\"crossbeam-utils/std\"]}}", + "crossbeam-epoch_0.9.20": "{\"dependencies\":[{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.18\"},{\"name\":\"loom-crate\",\"optional\":true,\"package\":\"loom\",\"req\":\"^0.7.1\",\"target\":\"cfg(crossbeam_loom)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"loom\":[\"loom-crate\",\"crossbeam-utils/loom\"],\"nightly\":[\"crossbeam-utils/nightly\"],\"std\":[\"alloc\",\"crossbeam-utils/std\"]}}", "crossbeam-utils_0.8.21": "{\"dependencies\":[{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7.1\",\"target\":\"cfg(crossbeam_loom)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"nightly\":[],\"std\":[]}}", "crunchy_0.2.4": "{\"dependencies\":[],\"features\":{\"default\":[\"limit_128\"],\"limit_1024\":[],\"limit_128\":[],\"limit_2048\":[],\"limit_256\":[],\"limit_512\":[],\"limit_64\":[],\"std\":[]}}", "crypto-bigint_0.5.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"der\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"generic-array\",\"optional\":true,\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand_chacha\",\"req\":\"^0.3\"},{\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6.4\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"rlp\",\"optional\":true,\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.4\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"serdect?/alloc\"],\"default\":[\"rand\"],\"extra-sizes\":[],\"rand\":[\"rand_core/std\"],\"serde\":[\"dep:serdect\"]}}", "crypto-common_0.1.6": "{\"dependencies\":[{\"features\":[\"more_lengths\"],\"name\":\"generic-array\",\"req\":\"^0.14.4\"},{\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"typenum\",\"req\":\"^1.14\"}],\"features\":{\"getrandom\":[\"rand_core/getrandom\"],\"std\":[]}}", "curve25519-dalek-derive_0.1.1": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.66\"},{\"name\":\"quote\",\"req\":\"^1.0.31\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.27\"}],\"features\":{}}", "curve25519-dalek_4.1.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2.6\",\"target\":\"cfg(target_arch = \\\"x86_64\\\")\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"curve25519-dalek-derive\",\"req\":\"^0.1\",\"target\":\"cfg(all(not(curve25519_dalek_backend = \\\"fiat\\\"), not(curve25519_dalek_backend = \\\"serial\\\"), target_arch = \\\"x86_64\\\"))\"},{\"default_features\":false,\"name\":\"digest\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"ff\",\"optional\":true,\"req\":\"^0.13\"},{\"default_features\":false,\"name\":\"fiat-crypto\",\"req\":\"^0.2.1\",\"target\":\"cfg(curve25519_dalek_backend = \\\"fiat\\\")\"},{\"default_features\":false,\"name\":\"group\",\"optional\":true,\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.2\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6.4\"},{\"default_features\":false,\"features\":[\"getrandom\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"kind\":\"build\",\"name\":\"rustc_version\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.3.0\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"zeroize?/alloc\"],\"default\":[\"alloc\",\"precomputed-tables\",\"zeroize\"],\"group\":[\"dep:group\",\"rand_core\"],\"group-bits\":[\"group\",\"ff/bits\"],\"legacy_compatibility\":[],\"precomputed-tables\":[]}}", - "darling_0.21.3": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.21.3\"},{\"name\":\"darling_macro\",\"req\":\"=0.21.3\"},{\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.86\"},{\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.9\",\"target\":\"cfg(compiletests)\"},{\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.15\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.89\",\"target\":\"cfg(compiletests)\"}],\"features\":{\"default\":[\"suggestions\"],\"diagnostics\":[\"darling_core/diagnostics\"],\"serde\":[\"darling_core/serde\"],\"suggestions\":[\"darling_core/suggestions\"]}}", - "darling_core_0.21.3": "{\"dependencies\":[{\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"name\":\"ident_case\",\"req\":\"^1.0.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.86\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.210\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.140\"},{\"name\":\"strsim\",\"optional\":true,\"req\":\"^0.11.1\"},{\"features\":[\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{\"diagnostics\":[],\"suggestions\":[\"strsim\"]}}", - "darling_macro_0.21.3": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.21.3\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{}}", + "darling_0.23.0": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.23.0\"},{\"name\":\"darling_macro\",\"req\":\"=0.23.0\"},{\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.86\"},{\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.9\",\"target\":\"cfg(compiletests)\"},{\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.15\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.89\",\"target\":\"cfg(compiletests)\"}],\"features\":{\"default\":[\"suggestions\"],\"diagnostics\":[\"darling_core/diagnostics\"],\"serde\":[\"darling_core/serde\"],\"suggestions\":[\"darling_core/suggestions\"]}}", + "darling_core_0.23.0": "{\"dependencies\":[{\"name\":\"ident_case\",\"req\":\"^1.0.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.86\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.210\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.140\"},{\"name\":\"strsim\",\"optional\":true,\"req\":\"^0.11.1\"},{\"features\":[\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{\"diagnostics\":[],\"suggestions\":[\"strsim\"]}}", + "darling_macro_0.23.0": "{\"dependencies\":[{\"name\":\"darling_core\",\"req\":\"=0.23.0\"},{\"name\":\"quote\",\"req\":\"^1.0.18\"},{\"name\":\"syn\",\"req\":\"^2.0.15\"}],\"features\":{}}", "data-encoding_2.11.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "der_0.7.10": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"const-oid\",\"optional\":true,\"req\":\"^0.9.2\"},{\"name\":\"der_derive\",\"optional\":true,\"req\":\"^0.7.2\"},{\"name\":\"flagset\",\"optional\":true,\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4.1\"},{\"features\":[\"alloc\"],\"name\":\"pem-rfc7468\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.4\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.5\"}],\"features\":{\"alloc\":[\"zeroize?/alloc\"],\"arbitrary\":[\"dep:arbitrary\",\"const-oid?/arbitrary\",\"std\"],\"bytes\":[\"dep:bytes\",\"alloc\"],\"derive\":[\"dep:der_derive\"],\"oid\":[\"dep:const-oid\"],\"pem\":[\"dep:pem-rfc7468\",\"alloc\",\"zeroize\"],\"real\":[],\"std\":[\"alloc\"]}}", "deranged_0.5.8": "{\"dependencies\":[{\"name\":\"deranged-macros\",\"optional\":true,\"req\":\"=0.3.0\"},{\"default_features\":false,\"name\":\"num-traits\",\"optional\":true,\"req\":\"^0.2.15\"},{\"default_features\":false,\"name\":\"powerfmt\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"name\":\"rand010\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"rand010\",\"package\":\"rand\",\"req\":\"^0.10.0\"},{\"default_features\":false,\"name\":\"rand08\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"rand08\",\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"name\":\"rand09\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand09\",\"package\":\"rand\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.86\"}],\"features\":{\"alloc\":[],\"default\":[],\"macros\":[\"dep:deranged-macros\"],\"num\":[\"dep:num-traits\"],\"powerfmt\":[\"dep:powerfmt\"],\"quickcheck\":[\"dep:quickcheck\",\"alloc\"],\"rand\":[\"rand08\",\"rand09\",\"rand010\"],\"rand010\":[\"dep:rand010\"],\"rand08\":[\"dep:rand08\"],\"rand09\":[\"dep:rand09\"],\"serde\":[\"dep:serde_core\"]}}", @@ -916,6 +820,7 @@ "digest_0.10.7": "{\"dependencies\":[{\"name\":\"blobby\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"block-buffer\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"const-oid\",\"optional\":true,\"req\":\"^0.9\"},{\"name\":\"crypto-common\",\"req\":\"^0.1.3\"},{\"default_features\":false,\"name\":\"subtle\",\"optional\":true,\"req\":\"^2.4\"}],\"features\":{\"alloc\":[],\"core-api\":[\"block-buffer\"],\"default\":[\"core-api\"],\"dev\":[\"blobby\"],\"mac\":[\"subtle\"],\"oid\":[\"const-oid\"],\"rand_core\":[\"crypto-common/rand_core\"],\"std\":[\"alloc\",\"crypto-common/std\"]}}", "dirs-sys_0.5.0": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(unix)\"},{\"name\":\"option-ext\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"redox_users\",\"req\":\"^0.5\",\"target\":\"cfg(target_os = \\\"redox\\\")\"},{\"features\":[\"Win32_UI_Shell\",\"Win32_Foundation\",\"Win32_Globalization\",\"Win32_System_Com\"],\"name\":\"windows-sys\",\"req\":\">=0.59.0\",\"target\":\"cfg(windows)\"}],\"features\":{}}", "dirs_6.0.0": "{\"dependencies\":[{\"name\":\"dirs-sys\",\"req\":\"^0.5.0\"}],\"features\":{}}", + "displaydoc_0.2.5": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.6.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^1.0.24\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "displaydoc_0.2.6": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^1.0.24\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "dunce_1.0.5": "{\"dependencies\":[],\"features\":{}}", "dyn-clone_1.0.19": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.66\"}],\"features\":{}}", @@ -931,14 +836,15 @@ "equivalent_1.0.2": "{\"dependencies\":[],\"features\":{}}", "errno_0.3.14": "{\"dependencies\":[{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(target_os=\\\"hermit\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(target_os=\\\"wasi\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(unix)\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Diagnostics_Debug\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"libc/std\"]}}", "event-listener-strategy_0.5.4": "{\"dependencies\":[{\"default_features\":false,\"name\":\"event-listener\",\"req\":\"^5.0.0\"},{\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2.0.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.12\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.37\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"}],\"features\":{\"default\":[\"std\"],\"loom\":[\"event-listener/loom\"],\"portable-atomic\":[\"event-listener/portable-atomic\"],\"std\":[\"event-listener/std\"]}}", - "event-listener_2.5.3": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"waker-fn\",\"req\":\"^1\"}],\"features\":{}}", "event-listener_5.4.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"concurrent-queue\",\"req\":\"^2.4.0\"},{\"default_features\":false,\"features\":[\"cargo_bench_support\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1.2.0\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"critical-section\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2.0.0\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"name\":\"parking\",\"optional\":true,\"req\":\"^2.0.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.12\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"portable-atomic-util\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"portable_atomic_crate\",\"optional\":true,\"package\":\"portable-atomic\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"try-lock\",\"req\":\"^0.2.5\"},{\"kind\":\"dev\",\"name\":\"waker-fn\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"}],\"features\":{\"default\":[\"std\"],\"loom\":[\"concurrent-queue/loom\",\"parking?/loom\",\"dep:loom\"],\"portable-atomic\":[\"portable-atomic-util\",\"portable_atomic_crate\",\"concurrent-queue/portable-atomic\"],\"std\":[\"concurrent-queue/std\",\"parking\"]}}", - "fastrand_1.9.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"instant\",\"req\":\"^0.1\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"features\":[\"wasm-bindgen\"],\"kind\":\"dev\",\"name\":\"instant\",\"req\":\"^0.1\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"kind\":\"dev\",\"name\":\"wyhash\",\"req\":\"^0.5\"}],\"features\":{}}", + "fallible-iterator_0.2.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[]}}", + "fastcdc_3.2.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"aes\",\"req\":\"^0.8.2\"},{\"name\":\"async-stream\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"byteorder\",\"req\":\"^1.4.3\"},{\"features\":[\"cargo\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.2.1\"},{\"kind\":\"dev\",\"name\":\"ctr\",\"req\":\"^0.9.2\"},{\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"futures-test\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"md-5\",\"req\":\"^0.10.5\"},{\"kind\":\"dev\",\"name\":\"memmap2\",\"req\":\"^0.9.5\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"fs\",\"io-util\",\"rt\",\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{\"default\":[],\"futures\":[\"dep:futures\"],\"tokio\":[\"dep:tokio\",\"tokio-stream\",\"async-stream\"]}}", "fastrand_2.3.0": "{\"dependencies\":[{\"features\":[\"js\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wyhash\",\"req\":\"^0.5\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"js\":[\"std\",\"getrandom\"],\"std\":[\"alloc\"]}}", "fastrand_2.4.1": "{\"dependencies\":[{\"features\":[\"wasm_js\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.4\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3.4\"},{\"features\":[\"wasm_js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3.4\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wyhash\",\"req\":\"^0.6\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"js\":[\"std\",\"getrandom\"],\"std\":[\"alloc\"]}}", "ff_0.13.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitvec\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"blake2b_simd\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"byteorder\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"ff_derive\",\"optional\":true,\"req\":\"^0.13.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"subtle\",\"req\":\"^2.2.1\"}],\"features\":{\"alloc\":[],\"bits\":[\"bitvec\"],\"default\":[\"bits\",\"std\"],\"derive\":[\"byteorder\",\"ff_derive\"],\"derive_bits\":[\"bits\",\"ff_derive/bits\"],\"std\":[\"alloc\"]}}", "fiat-crypto_0.2.9": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "filetime_0.2.26": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.27\",\"target\":\"cfg(unix)\"},{\"name\":\"libredox\",\"req\":\"^0.1.0\",\"target\":\"cfg(target_os = \\\"redox\\\")\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"},{\"features\":[\"Win32_Foundation\",\"Win32_Storage_FileSystem\"],\"name\":\"windows-sys\",\"req\":\"^0.60.0\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "filetime_0.2.29": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.27\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{}}", "find-msvc-tools_0.1.9": "{\"dependencies\":[],\"features\":{}}", "fixedbitset_0.5.7": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "flate2_1.1.9": "{\"dependencies\":[{\"name\":\"cloudflare-zlib-sys\",\"optional\":true,\"req\":\"^0.3.6\"},{\"name\":\"crc32fast\",\"optional\":true,\"req\":\"^1.2.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"libz-ng-sys\",\"optional\":true,\"req\":\"^1.1.16\"},{\"default_features\":false,\"name\":\"libz-sys\",\"optional\":true,\"req\":\"^1.1.20\"},{\"default_features\":false,\"features\":[\"with-alloc\",\"simd\"],\"name\":\"miniz_oxide\",\"req\":\"^0.8.5\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"emscripten\\\")))\"},{\"default_features\":false,\"features\":[\"with-alloc\",\"simd\"],\"name\":\"miniz_oxide\",\"optional\":true,\"req\":\"^0.8.5\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"std\",\"rust-allocator\"],\"name\":\"zlib-rs\",\"optional\":true,\"req\":\"^0.6.0\"}],\"features\":{\"any_c_zlib\":[\"any_zlib\"],\"any_impl\":[],\"any_zlib\":[\"any_impl\"],\"cloudflare_zlib\":[\"any_c_zlib\",\"cloudflare-zlib-sys\",\"dep:crc32fast\"],\"default\":[\"rust_backend\"],\"miniz-sys\":[\"rust_backend\"],\"miniz_oxide\":[\"any_impl\",\"dep:miniz_oxide\",\"dep:crc32fast\"],\"rust_backend\":[\"miniz_oxide\",\"any_impl\"],\"zlib\":[\"any_c_zlib\",\"libz-sys\",\"dep:crc32fast\"],\"zlib-default\":[\"any_c_zlib\",\"libz-sys/default\",\"dep:crc32fast\"],\"zlib-ng\":[\"any_c_zlib\",\"libz-ng-sys\",\"dep:crc32fast\"],\"zlib-ng-compat\":[\"zlib\",\"libz-sys/zlib-ng\",\"dep:crc32fast\"],\"zlib-rs\":[\"any_zlib\",\"dep:zlib-rs\"]}}", @@ -953,31 +859,33 @@ "futures-core_0.3.32": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.3\"}],\"features\":{\"alloc\":[],\"cfg-target-has-atomic\":[],\"default\":[\"std\"],\"std\":[\"alloc\"],\"unstable\":[]}}", "futures-executor_0.3.31": "{\"dependencies\":[{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-task\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-util\",\"req\":\"^0.3.31\"},{\"name\":\"num_cpus\",\"optional\":true,\"req\":\"^1.8.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"futures-core/std\",\"futures-task/std\",\"futures-util/std\"],\"thread-pool\":[\"std\",\"num_cpus\"]}}", "futures-io_0.3.32": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[],\"unstable\":[]}}", - "futures-lite_1.13.0": "{\"dependencies\":[{\"name\":\"fastrand\",\"optional\":true,\"req\":\"^1.3.4\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.5\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.5\"},{\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.3.3\"},{\"name\":\"parking\",\"optional\":true,\"req\":\"^2.0.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"spin_on\",\"req\":\"^0.1.0\"},{\"name\":\"waker-fn\",\"optional\":true,\"req\":\"^1.0.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\",\"fastrand\",\"futures-io\",\"parking\",\"memchr\",\"waker-fn\"]}}", "futures-macro_0.3.32": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.52\"}],\"features\":{}}", "futures-sink_0.3.32": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "futures-task_0.3.32": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"cfg-target-has-atomic\":[],\"default\":[\"std\"],\"std\":[\"alloc\"],\"unstable\":[]}}", "futures-util_0.3.32": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.32\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-macro\",\"optional\":true,\"req\":\"=0.3.32\"},{\"default_features\":false,\"name\":\"futures-sink\",\"optional\":true,\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-task\",\"req\":\"^0.3.32\"},{\"name\":\"futures_01\",\"optional\":true,\"package\":\"futures\",\"req\":\"^0.1.25\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.26\"},{\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.2\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.6\"},{\"default_features\":false,\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.7\"},{\"name\":\"spin\",\"optional\":true,\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^0.1.11\"},{\"name\":\"tokio-io\",\"optional\":true,\"req\":\"^0.1.9\"}],\"features\":{\"alloc\":[\"futures-core/alloc\",\"futures-task/alloc\",\"slab\"],\"async-await\":[],\"async-await-macro\":[\"async-await\",\"futures-macro\"],\"bilock\":[],\"cfg-target-has-atomic\":[],\"channel\":[\"std\",\"futures-channel\"],\"compat\":[\"std\",\"futures_01\",\"libc\"],\"default\":[\"std\",\"async-await\",\"async-await-macro\"],\"io\":[\"std\",\"futures-io\",\"memchr\"],\"io-compat\":[\"io\",\"compat\",\"tokio-io\",\"libc\"],\"portable-atomic\":[\"futures-core/portable-atomic\"],\"sink\":[\"futures-sink\"],\"std\":[\"alloc\",\"futures-core/std\",\"futures-task/std\",\"slab/std\"],\"unstable\":[\"futures-core/unstable\",\"futures-task/unstable\"],\"write-all-vectored\":[\"io\"]}}", "futures_0.3.31": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.3.0\"},{\"default_features\":false,\"features\":[\"sink\"],\"name\":\"futures-channel\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-executor\",\"optional\":true,\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-io\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-task\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"features\":[\"sink\"],\"name\":\"futures-util\",\"req\":\"^0.3.31\"},{\"kind\":\"dev\",\"name\":\"pin-project\",\"req\":\"^1.0.11\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^0.1.11\"}],\"features\":{\"alloc\":[\"futures-core/alloc\",\"futures-task/alloc\",\"futures-sink/alloc\",\"futures-channel/alloc\",\"futures-util/alloc\"],\"async-await\":[\"futures-util/async-await\",\"futures-util/async-await-macro\"],\"bilock\":[\"futures-util/bilock\"],\"cfg-target-has-atomic\":[],\"compat\":[\"std\",\"futures-util/compat\"],\"default\":[\"std\",\"async-await\",\"executor\"],\"executor\":[\"std\",\"futures-executor/std\"],\"io-compat\":[\"compat\",\"futures-util/io-compat\"],\"std\":[\"alloc\",\"futures-core/std\",\"futures-task/std\",\"futures-io/std\",\"futures-sink/std\",\"futures-util/std\",\"futures-util/io\",\"futures-util/channel\"],\"thread-pool\":[\"executor\",\"futures-executor/thread-pool\"],\"unstable\":[\"futures-core/unstable\",\"futures-task/unstable\",\"futures-channel/unstable\",\"futures-io/unstable\",\"futures-util/unstable\"],\"write-all-vectored\":[\"futures-util/write-all-vectored\"]}}", - "gcloud-auth_1.2.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"ctor\",\"req\":\"^0.5\"},{\"name\":\"google-cloud-metadata\",\"package\":\"gcloud-metadata\",\"req\":\"^1.0.1\"},{\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"home\",\"req\":\"^0.5\"},{\"default_features\":false,\"features\":[\"use_pem\"],\"name\":\"jsonwebtoken\",\"req\":\"^10.2\"},{\"name\":\"path-clean\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.3\"},{\"default_features\":false,\"features\":[\"json\",\"charset\"],\"name\":\"reqwest\",\"req\":\"^0.12.4\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"features\":[\"async_closure\"],\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.8.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"name\":\"time\",\"req\":\"^0.3\"},{\"name\":\"token-source\",\"req\":\"^1.0\"},{\"features\":[\"fs\"],\"name\":\"tokio\",\"req\":\"^1.32\"},{\"features\":[\"test-util\",\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.32\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\",\"std\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.4\"},{\"name\":\"urlencoding\",\"req\":\"^2.1\"}],\"features\":{\"default\":[\"default-tls\",\"jwt-aws-lc-rs\"],\"default-tls\":[\"reqwest/default-tls\"],\"external-account\":[\"sha2\",\"path-clean\",\"url\",\"percent-encoding\",\"hmac\",\"hex\"],\"hickory-dns\":[\"reqwest/hickory-dns\"],\"jwt-aws-lc-rs\":[\"jsonwebtoken/aws_lc_rs\"],\"jwt-rust-crypto\":[\"jsonwebtoken/rust_crypto\"],\"rustls-tls\":[\"reqwest/rustls-tls\"]}}", + "gcloud-auth_1.3.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"ctor\",\"req\":\"^0.5\"},{\"name\":\"google-cloud-metadata\",\"package\":\"gcloud-metadata\",\"req\":\"^1.0.2\"},{\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"home\",\"req\":\"^0.5\"},{\"default_features\":false,\"features\":[\"use_pem\"],\"name\":\"jsonwebtoken\",\"req\":\"^10.2\"},{\"name\":\"path-clean\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.3\"},{\"default_features\":false,\"features\":[\"json\",\"charset\",\"form\"],\"name\":\"reqwest\",\"req\":\"^0.13\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"features\":[\"async_closure\"],\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.8.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"name\":\"time\",\"req\":\"^0.3\"},{\"name\":\"token-source\",\"req\":\"^1.0\"},{\"features\":[\"fs\"],\"name\":\"tokio\",\"req\":\"^1.32\"},{\"features\":[\"test-util\",\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.32\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\",\"std\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.4\"},{\"name\":\"urlencoding\",\"req\":\"^2.1\"}],\"features\":{\"default\":[\"rustls-tls\",\"jwt-aws-lc-rs\"],\"external-account\":[\"sha2\",\"path-clean\",\"url\",\"percent-encoding\",\"hmac\",\"hex\"],\"hickory-dns\":[\"reqwest/hickory-dns\"],\"jwt-aws-lc-rs\":[\"jsonwebtoken/aws_lc_rs\"],\"jwt-rust-crypto\":[\"jsonwebtoken/rust_crypto\"],\"native-tls\":[\"reqwest/native-tls\"],\"rustls-no-provider\":[\"reqwest/rustls-no-provider\"],\"rustls-tls\":[\"reqwest/rustls\"]}}", "gcloud-metadata_1.0.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"reqwest\",\"req\":\"^0.13\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"features\":[\"sync\",\"net\",\"parking_lot\"],\"name\":\"tokio\",\"req\":\"^1.32\"},{\"features\":[\"test-util\",\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.32\"}],\"features\":{}}", - "gcloud-storage_1.1.1": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1.5\"},{\"kind\":\"dev\",\"name\":\"ctor\",\"req\":\"^0.5\"},{\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"google-cloud-auth\",\"optional\":true,\"package\":\"gcloud-auth\",\"req\":\"^1.1.2\"},{\"name\":\"google-cloud-metadata\",\"optional\":true,\"package\":\"gcloud-metadata\",\"req\":\"^1.0.1\"},{\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"req\":\"^1.18\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"features\":[\"pem\"],\"name\":\"pkcs8\",\"req\":\"^0.10\"},{\"name\":\"regex\",\"req\":\"^1.9\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"features\":[\"json\",\"multipart\"],\"name\":\"reqwest-middleware\",\"req\":\"^0.4\"},{\"name\":\"ring\",\"req\":\"^0.17\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.1\"},{\"name\":\"sha2\",\"req\":\"^0.10\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"features\":[\"std\",\"macros\",\"formatting\",\"parsing\",\"serde\"],\"name\":\"time\",\"req\":\"^0.3\"},{\"name\":\"token-source\",\"req\":\"^1.0\"},{\"features\":[\"macros\"],\"name\":\"tokio\",\"req\":\"^1.32\"},{\"features\":[\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.32\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.17\"},{\"name\":\"url\",\"req\":\"^2.4\"}],\"features\":{\"auth\":[\"google-cloud-auth\",\"google-cloud-metadata\"],\"default\":[\"default-tls\",\"auth\"],\"default-tls\":[\"reqwest/default-tls\",\"google-cloud-auth?/default-tls\"],\"external-account\":[\"google-cloud-auth?/external-account\"],\"hickory-dns\":[\"reqwest/hickory-dns\",\"google-cloud-auth?/hickory-dns\"],\"rustls-tls\":[\"reqwest/rustls-tls\",\"google-cloud-auth?/rustls-tls\"],\"trace\":[]}}", + "gcloud-storage_1.3.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1.5\"},{\"kind\":\"dev\",\"name\":\"ctor\",\"req\":\"^0.5\"},{\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"google-cloud-auth\",\"optional\":true,\"package\":\"gcloud-auth\",\"req\":\"^1.3.0\"},{\"name\":\"google-cloud-metadata\",\"optional\":true,\"package\":\"gcloud-metadata\",\"req\":\"^1.0.2\"},{\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"req\":\"^1.18\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"features\":[\"pem\"],\"name\":\"pkcs8\",\"req\":\"^0.10\"},{\"name\":\"regex\",\"req\":\"^1.9\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"name\":\"reqwest\",\"req\":\"^0.13\"},{\"features\":[\"json\",\"multipart\",\"query\"],\"name\":\"reqwest-middleware\",\"req\":\"^0.5\"},{\"name\":\"ring\",\"req\":\"^0.17\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3.1\"},{\"name\":\"sha2\",\"req\":\"^0.10\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"features\":[\"std\",\"macros\",\"formatting\",\"parsing\",\"serde\"],\"name\":\"time\",\"req\":\"^0.3\"},{\"name\":\"token-source\",\"req\":\"^1.0\"},{\"features\":[\"macros\"],\"name\":\"tokio\",\"req\":\"^1.32\"},{\"features\":[\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.32\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.17\"},{\"name\":\"url\",\"req\":\"^2.4\"}],\"features\":{\"auth\":[\"google-cloud-auth\",\"google-cloud-metadata\"],\"default\":[\"rustls-tls\",\"auth\",\"jwt-aws-lc-rs\"],\"external-account\":[\"google-cloud-auth?/external-account\"],\"hickory-dns\":[\"reqwest/hickory-dns\",\"google-cloud-auth?/hickory-dns\"],\"jwt-aws-lc-rs\":[\"google-cloud-auth?/jwt-aws-lc-rs\"],\"jwt-rust-crypto\":[\"google-cloud-auth?/jwt-rust-crypto\"],\"native-tls\":[\"google-cloud-auth?/native-tls\"],\"rustls-no-provider\":[\"google-cloud-auth?/rustls-no-provider\"],\"rustls-tls\":[\"google-cloud-auth?/rustls-tls\"],\"trace\":[]}}", "generic-array_0.14.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"typenum\",\"req\":\"^1.12\"},{\"kind\":\"build\",\"name\":\"version_check\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"more_lengths\":[]}}", - "getrandom_0.1.16": "{\"dependencies\":[{\"name\":\"bindgen\",\"optional\":true,\"package\":\"wasm-bindgen\",\"req\":\"^0.2.29\",\"target\":\"wasm32-unknown-unknown\"},{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"wasm32-unknown-unknown\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.64\",\"target\":\"cfg(unix)\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"stdweb\",\"optional\":true,\"req\":\"^0.4.18\",\"target\":\"wasm32-unknown-unknown\"},{\"name\":\"wasi\",\"req\":\"^0.9\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.2\",\"target\":\"wasm32-unknown-unknown\"}],\"features\":{\"dummy\":[],\"rustc-dep-of-std\":[\"compiler_builtins\",\"core\"],\"std\":[],\"test-in-browser\":[\"wasm-bindgen\"],\"wasm-bindgen\":[\"bindgen\",\"js-sys\"]}}", "getrandom_0.2.16": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(unix)\"},{\"default_features\":false,\"name\":\"wasi\",\"req\":\"^0.11\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.62\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.18\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"}],\"features\":{\"custom\":[],\"js\":[\"wasm-bindgen\",\"js-sys\"],\"linux_disable_fallback\":[],\"rdrand\":[],\"rustc-dep-of-std\":[\"compiler_builtins\",\"core\",\"libc/rustc-dep-of-std\",\"wasi/rustc-dep-of-std\"],\"std\":[],\"test-in-browser\":[]}}", + "getrandom_0.2.17": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(unix)\"},{\"default_features\":false,\"name\":\"wasi\",\"req\":\"^0.11\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.62\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.18\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"}],\"features\":{\"custom\":[],\"js\":[\"wasm-bindgen\",\"js-sys\"],\"linux_disable_fallback\":[],\"rdrand\":[],\"rustc-dep-of-std\":[\"compiler_builtins\",\"core\",\"libc/rustc-dep-of-std\",\"wasi/rustc-dep-of-std\"],\"std\":[],\"test-in-browser\":[]}}", "getrandom_0.3.4": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.77\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"), target_feature = \\\"atomics\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"netbsd\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"solaris\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"vxworks\\\")\"},{\"default_features\":false,\"name\":\"r-efi\",\"req\":\"^5.1\",\"target\":\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\"},{\"default_features\":false,\"name\":\"wasip2\",\"req\":\"^1\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.98\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"}],\"features\":{\"std\":[],\"wasm_js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"]}}", "getrandom_0.4.2": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.77\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"), target_feature = \\\"atomics\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"netbsd\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"solaris\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"vxworks\\\")\"},{\"default_features\":false,\"name\":\"r-efi\",\"req\":\"^6\",\"target\":\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\"},{\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.10.0\"},{\"default_features\":false,\"name\":\"wasip2\",\"req\":\"^1\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\"},{\"name\":\"wasip3\",\"req\":\"^0.4\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.98\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"}],\"features\":{\"std\":[],\"sys_rng\":[\"dep:rand_core\"],\"wasm_js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"]}}", - "ginepro_0.9.3": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1\"},{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"features\":[\"tokio\"],\"name\":\"hickory-resolver\",\"req\":\"^0.26\"},{\"name\":\"http\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"full\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"router\",\"transport\",\"codegen\",\"prost\"],\"name\":\"tonic\",\"req\":\"^0.13\"},{\"default_features\":false,\"features\":[\"discover\"],\"name\":\"tower\",\"req\":\"^0.5\"},{\"name\":\"tracing\",\"req\":\"^0.1\"}],\"features\":{\"default\":[\"tls-ring\"],\"tls-aws-lc\":[\"tonic/tls-aws-lc\"],\"tls-ring\":[\"tonic/tls-ring\"]}}", + "gimli_0.26.2": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"crossbeam\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"fallible-iterator\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"getopts\",\"req\":\"^0.2\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"memmap2\",\"req\":\"^0.5.5\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1\"},{\"features\":[\"wasm\"],\"kind\":\"dev\",\"name\":\"object\",\"req\":\"^0.29.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"test-assembler\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"typed-arena\",\"req\":\"^2\"}],\"features\":{\"default\":[\"read\",\"write\",\"std\",\"fallible-iterator\",\"endian-reader\"],\"endian-reader\":[\"read\",\"stable_deref_trait\"],\"read\":[\"read-core\"],\"read-core\":[],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"compiler_builtins\"],\"std\":[\"fallible-iterator/std\",\"stable_deref_trait/std\"],\"write\":[\"indexmap\"]}}", + "git+https://github.com/mstyura/ginepro?rev=d08cdeff6300edfb46204b3b9fbde3f3355db35f#d08cdeff6300edfb46204b3b9fbde3f3355db35f_ginepro": "{\"dependencies\":[{\"name\":\"anyhow\"},{\"name\":\"async-trait\"},{\"default_features\":true,\"features\":[\"tokio\"],\"name\":\"hickory-resolver\",\"optional\":false},{\"name\":\"http\"},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[\"full\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":false,\"features\":[\"router\",\"transport\",\"codegen\"],\"name\":\"tonic\",\"optional\":false},{\"default_features\":false,\"features\":[\"discover\"],\"name\":\"tower\",\"optional\":false},{\"name\":\"tracing\"}],\"features\":{\"default\":[\"tls-ring\"],\"tls-aws-lc\":[\"tonic/tls-aws-lc\"],\"tls-ring\":[\"tonic/tls-ring\"]},\"strip_prefix\":\"ginepro\"}", "goblin_0.10.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"plain\",\"req\":\"^0.2.3\"},{\"default_features\":false,\"name\":\"scroll\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"stderrlog\",\"req\":\"^0.6.0\"}],\"features\":{\"alloc\":[\"scroll/derive\",\"log\"],\"archive\":[\"alloc\"],\"default\":[\"std\",\"elf32\",\"elf64\",\"mach32\",\"mach64\",\"pe32\",\"pe64\",\"te\",\"archive\",\"endian_fd\"],\"elf32\":[],\"elf64\":[],\"endian_fd\":[\"alloc\"],\"mach32\":[\"alloc\",\"endian_fd\",\"archive\"],\"mach64\":[\"alloc\",\"endian_fd\",\"archive\"],\"pe32\":[\"alloc\",\"endian_fd\"],\"pe64\":[\"alloc\",\"endian_fd\"],\"std\":[\"alloc\",\"scroll/std\"],\"te\":[\"alloc\",\"endian_fd\"]}}", "group_0.13.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ff\",\"req\":\"^0.13\"},{\"name\":\"memuse\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"name\":\"rand_xorshift\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.2.1\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"],\"tests\":[\"alloc\",\"rand\",\"rand_xorshift\"],\"wnaf-memuse\":[\"alloc\",\"memuse\"]}}", "h2_0.4.13": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", "h2_0.4.14": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", "half_2.7.1": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.4.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.4.1\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"crunchy\",\"req\":\"^0.2.2\",\"target\":\"cfg(target_arch = \\\"spirv\\\")\"},{\"kind\":\"dev\",\"name\":\"crunchy\",\"req\":\"^0.2.2\"},{\"default_features\":false,\"features\":[\"libm\"],\"name\":\"num-traits\",\"optional\":true,\"req\":\"^0.2.16\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"thread_rng\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"rand_distr\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.8.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"derive\",\"simd\"],\"name\":\"zerocopy\",\"req\":\"^0.8.26\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"nightly\":[],\"rand_distr\":[\"dep:rand\",\"dep:rand_distr\"],\"std\":[\"alloc\"],\"use-intrinsics\":[],\"zerocopy\":[]}}", "hashbrown_0.12.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.7.0\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"bumpalo\",\"optional\":true,\"req\":\"^3.5.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"ahash-compile-time-rng\":[\"ahash/compile-time-rng\"],\"default\":[\"ahash\",\"inline-more\"],\"inline-more\":[],\"nightly\":[],\"raw\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"compiler_builtins\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", + "hashbrown_0.14.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.8.7\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.42\"},{\"features\":[\"validation\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7.42\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"ahash\",\"inline-more\",\"allocator-api2\"],\"inline-more\":[],\"nightly\":[\"allocator-api2?/nightly\",\"bumpalo/allocator_api\"],\"raw\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"compiler_builtins\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", "hashbrown_0.15.5": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.1.2\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.2\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", "hashbrown_0.16.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(unix)\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"foldhash?/nightly\",\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[],\"serde\":[\"dep:serde_core\",\"dep:serde\"]}}", "hashbrown_0.17.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(unix)\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"foldhash?/nightly\",\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[],\"serde\":[\"dep:serde_core\",\"dep:serde\"]}}", "heck_0.5.0": "{\"dependencies\":[],\"features\":{}}", + "hermit-abi_0.5.2": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[],\"rustc-dep-of-std\":[\"core\",\"alloc\"]}}", "hex_0.4.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"faster-hex\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"rustc-hex\",\"req\":\"^2.1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"version-sync\",\"req\":\"^0.9\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "hickory-net_0.26.1": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1.43\"},{\"default_features\":false,\"features\":[\"prebuilt-nasm\"],\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.12.3\"},{\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.4.1\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"data-encoding\",\"req\":\"^2.2.0\"},{\"default_features\":false,\"features\":[\"alloc\",\"std\"],\"name\":\"futures-channel\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"futures-executor\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-io\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"features\":[\"alloc\",\"async-await-macro\",\"std\"],\"name\":\"futures-util\",\"req\":\"^0.3.5\"},{\"features\":[\"stream\"],\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4.0\"},{\"name\":\"h3\",\"optional\":true,\"req\":\"^0.0.8\"},{\"name\":\"h3-quinn\",\"optional\":true,\"req\":\"^0.0.10\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"hickory-proto\",\"req\":\"^0.26.0\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"default_features\":false,\"features\":[\"alloc\",\"compiled_data\"],\"name\":\"idna\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"name\":\"ipnet\",\"req\":\"^2.3.0\"},{\"name\":\"jni\",\"req\":\"^0.22.1\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"lru-cache\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"log\",\"runtime-tokio\"],\"name\":\"quinn\",\"optional\":true,\"req\":\"^0.11.2\"},{\"default_features\":false,\"features\":[\"alloc\",\"std_rng\"],\"name\":\"rand\",\"req\":\"^0.10.0\"},{\"features\":[\"std\"],\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"default_features\":false,\"features\":[\"logging\",\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.23\"},{\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1.10\"},{\"name\":\"rustls-platform-verifier\",\"optional\":true,\"req\":\"^0.7\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"name\":\"time\",\"optional\":true,\"req\":\"^0.3\"},{\"features\":[\"alloc\"],\"name\":\"tinyvec\",\"req\":\"^1.1.1\"},{\"features\":[\"io-util\",\"macros\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.21\"},{\"features\":[\"rt\",\"time\",\"macros\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.21\"},{\"default_features\":false,\"features\":[\"early-data\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26\"},{\"default_features\":false,\"name\":\"tracing\",\"req\":\"^0.1.30\"},{\"default_features\":false,\"name\":\"url\",\"req\":\"^2.5.4\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"__dnssec\":[\"dep:bitflags\",\"dep:rustls-pki-types\",\"dep:time\",\"dep:lru-cache\",\"dep:parking_lot\"],\"__h3\":[\"dep:h3\",\"dep:h3-quinn\",\"dep:http\"],\"__https\":[\"dep:bytes\",\"dep:h2\",\"dep:http\"],\"__quic\":[\"dep:bytes\",\"dep:pin-project-lite\",\"dep:quinn\"],\"__tls\":[\"dep:bytes\",\"dep:rustls\",\"dep:tokio-rustls\",\"tokio\"],\"default\":[\"tokio\"],\"dnssec-aws-lc-rs\":[\"dep:aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/ring-io\",\"hickory-proto/dnssec-aws-lc-rs\",\"__dnssec\"],\"dnssec-ring\":[\"dep:ring\",\"hickory-proto/dnssec-ring\",\"__dnssec\"],\"h3-aws-lc-rs\":[\"quic-aws-lc-rs\",\"__h3\"],\"h3-ring\":[\"quic-ring\",\"__h3\"],\"https-aws-lc-rs\":[\"tls-aws-lc-rs\",\"__https\"],\"https-ring\":[\"tls-ring\",\"__https\"],\"mdns\":[\"socket2/all\"],\"quic-aws-lc-rs\":[\"quinn/rustls-aws-lc-rs\",\"tls-aws-lc-rs\",\"__quic\"],\"quic-ring\":[\"quinn/rustls-ring\",\"tls-ring\",\"__quic\"],\"rustls-platform-verifier\":[\"dep:rustls-platform-verifier\"],\"serde\":[\"dep:serde\",\"url/serde\"],\"tls-aws-lc-rs\":[\"tokio-rustls/aws-lc-rs\",\"__tls\"],\"tls-ring\":[\"tokio-rustls/ring\",\"__tls\"],\"tokio\":[\"dep:tokio\",\"tokio/net\",\"tokio/rt\",\"tokio/time\",\"tokio/rt-multi-thread\"]}}", "hickory-proto_0.26.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"prebuilt-nasm\"],\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.12.3\"},{\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.4.1\"},{\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1.1.1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"data-encoding\",\"req\":\"^2.2.0\"},{\"default_features\":false,\"features\":[\"alloc\",\"compiled_data\"],\"name\":\"idna\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"name\":\"ipnet\",\"req\":\"^2.3.0\"},{\"name\":\"jni\",\"req\":\"^0.22.1\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.44\"},{\"default_features\":false,\"features\":[\"critical-section\"],\"name\":\"once_cell\",\"req\":\"^1.20.0\"},{\"name\":\"prefix-trie\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"alloc\",\"std_rng\"],\"name\":\"rand\",\"req\":\"^0.10.0\"},{\"features\":[\"std\"],\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1.10\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"name\":\"time\",\"optional\":true,\"req\":\"^0.3\"},{\"features\":[\"alloc\"],\"name\":\"tinyvec\",\"req\":\"^1.1.1\"},{\"default_features\":false,\"name\":\"tracing\",\"req\":\"^0.1.30\"},{\"default_features\":false,\"name\":\"url\",\"req\":\"^2.5.4\"},{\"name\":\"wasm-bindgen-crate\",\"optional\":true,\"package\":\"wasm-bindgen\",\"req\":\"^0.2.58\"}],\"features\":{\"__dnssec\":[\"dep:bitflags\",\"dep:rustls-pki-types\",\"dep:time\",\"std\"],\"access-control\":[\"std\",\"dep:prefix-trie\"],\"default\":[\"std\"],\"dnssec-aws-lc-rs\":[\"dep:aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/ring-io\",\"__dnssec\"],\"dnssec-ring\":[\"dep:ring\",\"__dnssec\"],\"mdns\":[],\"no-std-rand\":[\"once_cell/critical-section\",\"dep:critical-section\"],\"serde\":[\"dep:serde\",\"std\",\"url/serde\"],\"std\":[\"data-encoding/std\",\"ipnet/std\",\"rand/std\",\"rand/thread_rng\",\"ring?/std\",\"thiserror/std\",\"tracing/std\",\"url/std\"],\"testing\":[\"std\"],\"wasm-bindgen\":[\"dep:wasm-bindgen-crate\",\"dep:js-sys\"]}}", @@ -988,7 +896,6 @@ "http-body-util_0.1.3": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"macros\",\"rt\",\"sync\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"}],\"features\":{\"channel\":[\"dep:tokio\"],\"default\":[],\"full\":[\"channel\"]}}", "http-body_0.4.6": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"http\",\"req\":\"^0.2\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"}],\"features\":{}}", "http-body_1.0.1": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"http\",\"req\":\"^1\"}],\"features\":{}}", - "http-types_2.12.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.26\"},{\"name\":\"async-channel\",\"req\":\"^1.5.1\"},{\"name\":\"async-std\",\"optional\":true,\"req\":\"^1.6.0\"},{\"features\":[\"attributes\"],\"kind\":\"dev\",\"name\":\"async-std\",\"req\":\"^1.6.0\"},{\"name\":\"base64\",\"req\":\"^0.13.0\"},{\"features\":[\"percent-encode\"],\"name\":\"cookie\",\"optional\":true,\"req\":\"^0.14.0\"},{\"name\":\"futures-lite\",\"req\":\"^1.11.1\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^0.2.0\"},{\"name\":\"infer\",\"req\":\"^0.2.3\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.0\"},{\"name\":\"rand\",\"req\":\"^0.7.3\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.106\"},{\"name\":\"serde_json\",\"req\":\"^1.0.51\"},{\"name\":\"serde_qs\",\"req\":\"^0.8.3\"},{\"name\":\"serde_urlencoded\",\"req\":\"^0.7.0\"},{\"features\":[\"serde\"],\"name\":\"url\",\"req\":\"^2.1.1\"}],\"features\":{\"async_std\":[\"fs\"],\"cookie-secure\":[\"cookies\",\"cookie/secure\"],\"cookies\":[\"cookie\"],\"default\":[\"fs\",\"cookie-secure\"],\"docs\":[\"unstable\"],\"fs\":[\"async-std\"],\"hyperium_http\":[\"http\"],\"unstable\":[]}}", "http_0.2.12": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"kind\":\"dev\",\"name\":\"indexmap\",\"req\":\"<=1.8\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.7.0\"},{\"kind\":\"dev\",\"name\":\"seahash\",\"req\":\"^3.0.5\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{}}", "http_1.4.0": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "http_1.4.1": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", @@ -1017,8 +924,6 @@ "indexmap_1.9.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"raw\"],\"name\":\"hashbrown\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.4.1\"},{\"name\":\"rustc-rayon\",\"optional\":true,\"package\":\"rustc-rayon\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"}],\"features\":{\"serde-1\":[\"serde\"],\"std\":[],\"test_debug\":[],\"test_low_transition_point\":[]}}", "indexmap_2.13.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"equivalent\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"hashbrown\",\"req\":\"^0.16.1\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde_core\",\"dep:serde\"],\"std\":[],\"test_debug\":[]}}", "indexmap_2.14.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"equivalent\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"hashbrown\",\"req\":\"^0.17\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.1\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde_core\",\"dep:serde\"],\"std\":[],\"test_debug\":[]}}", - "infer_0.2.3": "{\"dependencies\":[],\"features\":{}}", - "instant_0.1.13": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"asmjs-unknown-emscripten\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"wasm32-unknown-emscripten\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"wasm32-unknown-unknown\"},{\"name\":\"stdweb\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"asmjs-unknown-emscripten\"},{\"name\":\"stdweb\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"wasm32-unknown-emscripten\"},{\"name\":\"stdweb\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"wasm32-unknown-unknown\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\"},{\"name\":\"wasm-bindgen_rs\",\"optional\":true,\"package\":\"wasm-bindgen\",\"req\":\"^0.2\",\"target\":\"asmjs-unknown-emscripten\"},{\"name\":\"wasm-bindgen_rs\",\"optional\":true,\"package\":\"wasm-bindgen\",\"req\":\"^0.2\",\"target\":\"wasm32-unknown-emscripten\"},{\"name\":\"wasm-bindgen_rs\",\"optional\":true,\"package\":\"wasm-bindgen\",\"req\":\"^0.2\",\"target\":\"wasm32-unknown-unknown\"},{\"features\":[\"Window\",\"Performance\",\"PerformanceTiming\"],\"name\":\"web-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"asmjs-unknown-emscripten\"},{\"features\":[\"Window\",\"Performance\",\"PerformanceTiming\"],\"name\":\"web-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"wasm32-unknown-emscripten\"},{\"features\":[\"Window\",\"Performance\",\"PerformanceTiming\"],\"name\":\"web-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"wasm32-unknown-unknown\"}],\"features\":{\"inaccurate\":[],\"now\":[],\"wasm-bindgen\":[\"js-sys\",\"wasm-bindgen_rs\",\"web-sys\"]}}", "io-lifetimes_2.0.4": "{\"dependencies\":[{\"features\":[\"io_safety\"],\"name\":\"async-std\",\"optional\":true,\"req\":\"^1.13.0\",\"target\":\"cfg(not(target_os = \\\"wasi\\\"))\"},{\"name\":\"hermit-abi\",\"optional\":true,\"req\":\">=0.3, <=0.4\",\"target\":\"cfg(target_os = \\\"hermit\\\")\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.96\",\"target\":\"cfg(not(windows))\"},{\"features\":[\"net\",\"os-ext\"],\"name\":\"mio\",\"optional\":true,\"req\":\"^0.8.0\",\"target\":\"cfg(not(target_os = \\\"wasi\\\"))\"},{\"features\":[\"io_safety\"],\"name\":\"os_pipe\",\"optional\":true,\"req\":\"^1.0.0\",\"target\":\"cfg(not(target_os = \\\"wasi\\\"))\"},{\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_os = \\\"wasi\\\"))\"},{\"features\":[\"io-std\",\"fs\",\"net\",\"process\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.6.0\",\"target\":\"cfg(not(target_os = \\\"wasi\\\"))\"},{\"features\":[\"Win32_Foundation\",\"Win32_Storage_FileSystem\",\"Win32_Networking_WinSock\",\"Win32_Security\",\"Win32_System_IO\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52, <=0.59\",\"target\":\"cfg(windows)\"}],\"features\":{\"close\":[\"libc\",\"hermit-abi\",\"windows-sys\"],\"default\":[]}}", "ipconfig_0.3.4": "{\"dependencies\":[{\"name\":\"socket2\",\"req\":\"^0.6.0\",\"target\":\"cfg(windows)\"},{\"name\":\"widestring\",\"req\":\"^1.0.2\",\"target\":\"cfg(windows)\"},{\"name\":\"windows-registry\",\"optional\":true,\"req\":\"^0.6.1\",\"target\":\"cfg(windows)\"},{\"name\":\"windows-result\",\"optional\":true,\"req\":\"^0.4.1\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\",\"Win32_System_Registry\"],\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"computer\":[\"dep:windows-registry\",\"dep:windows-result\"],\"default\":[\"computer\"]}}", "ipnet_2.11.0": "{\"dependencies\":[{\"name\":\"heapless\",\"optional\":true,\"req\":\"^0\"},{\"name\":\"schemars\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"package\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"json\":[\"serde\",\"schemars\"],\"ser_as_str\":[\"heapless\"],\"std\":[]}}", @@ -1028,7 +933,9 @@ "itoa_1.0.17": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{}}", "itoa_1.0.18": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{}}", "jiff-static_0.2.23": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.93\"},{\"name\":\"quote\",\"req\":\"^1.0.38\"},{\"name\":\"syn\",\"req\":\"^2.0.98\"}],\"features\":{\"default\":[],\"perf-inline\":[],\"tz-fat\":[],\"tzdb\":[\"dep:jiff-tzdb\"]}}", + "jiff-static_0.2.24": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.93\"},{\"name\":\"quote\",\"req\":\"^1.0.38\"},{\"name\":\"syn\",\"req\":\"^2.0.98\"}],\"features\":{\"default\":[],\"perf-inline\":[],\"tz-fat\":[],\"tzdb\":[\"dep:jiff-tzdb\"]}}", "jiff_0.2.23": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.81\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.38\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"hifitime\",\"req\":\"^3.9.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"humantime\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.39.0\"},{\"name\":\"jiff-static\",\"req\":\"=0.2.23\",\"target\":\"cfg(any())\"},{\"name\":\"jiff-static\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"jiff-tzdb-platform\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(any(windows, target_family = \\\"wasm\\\"))\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.50\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"req\":\"^1.10.0\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"name\":\"portable-atomic-util\",\"req\":\"^0.2.4\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.203\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.34\"},{\"kind\":\"dev\",\"name\":\"tabwriter\",\"req\":\"^1.4.0\"},{\"features\":[\"local-offset\",\"macros\",\"parsing\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.36\"},{\"kind\":\"dev\",\"name\":\"time-tz\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"tzfile\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5.0\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.70\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_System_Time\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"portable-atomic-util/alloc\"],\"default\":[\"std\",\"tz-system\",\"tz-fat\",\"tzdb-bundle-platform\",\"tzdb-zoneinfo\",\"tzdb-concatenated\",\"perf-inline\"],\"js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"],\"logging\":[\"dep:log\"],\"perf-inline\":[],\"serde\":[\"dep:serde_core\"],\"static\":[\"static-tz\",\"jiff-static?/tzdb\"],\"static-tz\":[\"dep:jiff-static\"],\"std\":[\"alloc\",\"log?/std\",\"serde_core?/std\"],\"tz-fat\":[\"jiff-static?/tz-fat\"],\"tz-system\":[\"std\",\"dep:windows-sys\"],\"tzdb-bundle-always\":[\"dep:jiff-tzdb\",\"alloc\"],\"tzdb-bundle-platform\":[\"dep:jiff-tzdb-platform\",\"alloc\"],\"tzdb-concatenated\":[\"std\"],\"tzdb-zoneinfo\":[\"std\"]}}", + "jiff_0.2.24": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.81\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.38\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"hifitime\",\"req\":\"^3.9.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"humantime\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.39.0\"},{\"name\":\"jiff-static\",\"req\":\"=0.2.24\",\"target\":\"cfg(any())\"},{\"name\":\"jiff-static\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"jiff-tzdb-platform\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(any(windows, target_family = \\\"wasm\\\"))\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.50\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"req\":\"^1.10.0\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"name\":\"portable-atomic-util\",\"req\":\"^0.2.4\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.203\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.34\"},{\"kind\":\"dev\",\"name\":\"tabwriter\",\"req\":\"^1.4.0\"},{\"features\":[\"local-offset\",\"macros\",\"parsing\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.36\"},{\"kind\":\"dev\",\"name\":\"time-tz\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"tzfile\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5.0\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.70\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_System_Time\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"portable-atomic-util/alloc\"],\"default\":[\"std\",\"tz-system\",\"tz-fat\",\"tzdb-bundle-platform\",\"tzdb-zoneinfo\",\"tzdb-concatenated\",\"perf-inline\"],\"js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"],\"logging\":[\"dep:log\"],\"perf-inline\":[],\"serde\":[\"dep:serde_core\"],\"static\":[\"static-tz\",\"jiff-static?/tzdb\"],\"static-tz\":[\"dep:jiff-static\"],\"std\":[\"alloc\",\"log?/std\",\"serde_core?/std\"],\"tz-fat\":[\"jiff-static?/tz-fat\"],\"tz-system\":[\"std\",\"dep:windows-sys\"],\"tzdb-bundle-always\":[\"dep:jiff-tzdb\",\"alloc\"],\"tzdb-bundle-platform\":[\"dep:jiff-tzdb-platform\",\"alloc\"],\"tzdb-concatenated\":[\"std\"],\"tzdb-zoneinfo\":[\"std\"]}}", "jni-macros_0.22.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"javac\",\"req\":\"^0.1.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"build\",\"name\":\"rustc_version\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rusty-fork\",\"req\":\"^0.3.0\"},{\"name\":\"simd_cesu8\",\"req\":\"^1.0.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1\"}],\"features\":{}}", "jni-sys-macros_0.4.1": "{\"dependencies\":[{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", "jni-sys_0.3.0": "{\"dependencies\":[],\"features\":{}}", @@ -1036,9 +943,12 @@ "jni_0.21.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.13.0\",\"target\":\"cfg(windows)\"},{\"name\":\"cesu8\",\"req\":\"^1.1.0\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"combine\",\"req\":\"^4.1.0\"},{\"name\":\"java-locator\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"jni-sys\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"name\":\"libloading\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"kind\":\"dev\",\"name\":\"rusty-fork\",\"req\":\"^0.3.0\"},{\"name\":\"thiserror\",\"req\":\"^1.0.20\"},{\"kind\":\"build\",\"name\":\"walkdir\",\"req\":\"^2\"},{\"features\":[\"Win32_Globalization\"],\"name\":\"windows-sys\",\"req\":\"^0.45.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[],\"invocation\":[\"java-locator\",\"libloading\"]}}", "jni_0.22.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.13.0\",\"target\":\"cfg(windows)\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"combine\",\"req\":\"^4.1.0\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"name\":\"java-locator\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(not(target_os = \\\"android\\\"))\"},{\"kind\":\"dev\",\"name\":\"javac\",\"req\":\"^0.1.0\"},{\"name\":\"jni-macros\",\"req\":\"=0.22.4\"},{\"name\":\"jni-sys\",\"req\":\"^0.4.1\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"name\":\"libloading\",\"optional\":true,\"req\":\"^0.8\",\"target\":\"cfg(not(target_os = \\\"android\\\"))\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"kind\":\"dev\",\"name\":\"rusty-fork\",\"req\":\"^0.3.0\"},{\"name\":\"simd_cesu8\",\"req\":\"^1.1.1\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1\"},{\"kind\":\"build\",\"name\":\"walkdir\",\"req\":\"^2\"},{\"name\":\"windows-link\",\"req\":\"^0.2\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_System_Threading\",\"Win32_Foundation\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"_cfg_test\":[],\"default\":[],\"invocation\":[\"dep:java-locator\",\"dep:libloading\"]}}", "jobserver_0.1.34": "{\"dependencies\":[{\"features\":[\"std\"],\"name\":\"getrandom\",\"req\":\"^0.3.2\",\"target\":\"cfg(windows)\"},{\"name\":\"libc\",\"req\":\"^0.2.171\",\"target\":\"cfg(unix)\"},{\"features\":[\"fs\"],\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.28.0\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.10.1\"}],\"features\":{}}", - "js-sys_0.3.81": "{\"dependencies\":[{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.104\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"wasm-bindgen/std\"]}}", + "js-sys_0.3.102": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.8\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.31\"},{\"kind\":\"dev\",\"name\":\"half\",\"req\":\"^2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.125\"}],\"features\":{\"default\":[\"std\",\"unsafe-eval\"],\"futures-core-03-stream\":[\"dep:futures-util\",\"dep:futures-core\"],\"std\":[\"wasm-bindgen/std\",\"dep:futures-util\"],\"unsafe-eval\":[]}}", + "js-sys_0.3.82": "{\"dependencies\":[{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"wasm-bindgen/std\"]}}", + "jsonc-parser_0.26.2": "{\"dependencies\":[{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.6\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.0.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2.0\"}],\"features\":{\"cst\":[],\"error_unicode_width\":[\"unicode-width\"],\"preserve_order\":[\"indexmap\",\"serde_json/preserve_order\"],\"serde\":[\"serde_json\"]}}", "jsonwebtoken_10.3.0": "{\"dependencies\":[{\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.15.0\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\")))))\"},{\"features\":[\"pkcs8\"],\"name\":\"ed25519-dalek\",\"optional\":true,\"req\":\"^2.1.1\"},{\"features\":[\"pkcs8\",\"rand_core\"],\"kind\":\"dev\",\"name\":\"ed25519-dalek\",\"req\":\"^2.1.1\"},{\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"hmac\",\"optional\":true,\"req\":\"^0.12.1\"},{\"name\":\"js-sys\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"features\":[\"ecdsa\"],\"name\":\"p256\",\"optional\":true,\"req\":\"^0.13.2\"},{\"features\":[\"ecdsa\"],\"name\":\"p384\",\"optional\":true,\"req\":\"^0.13.0\"},{\"name\":\"pem\",\"optional\":true,\"req\":\"^3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8.5\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6.4\"},{\"name\":\"rsa\",\"optional\":true,\"req\":\"^0.9.6\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.228\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"oid\"],\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10.7\"},{\"features\":[\"std\"],\"name\":\"signature\",\"req\":\"^2.2.0\"},{\"name\":\"simple_asn1\",\"optional\":true,\"req\":\"^0.6\"},{\"features\":[\"wasm-bindgen\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\")))))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.1\"}],\"features\":{\"aws_lc_rs\":[\"aws-lc-rs\"],\"default\":[\"use_pem\"],\"rust_crypto\":[\"ed25519-dalek\",\"hmac\",\"p256\",\"p384\",\"rand\",\"rsa\",\"sha2\"],\"use_pem\":[\"pem\",\"simple_asn1\"]}}", "lazy_static_1.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"features\":[\"once\"],\"name\":\"spin\",\"optional\":true,\"req\":\"^0.9.8\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1\"}],\"features\":{\"spin_no_std\":[\"spin\"]}}", + "leb128_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.1\"}],\"features\":{\"nightly\":[]}}", "leb128fmt_0.1.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[]}}", "libc_0.2.183": "{\"dependencies\":[{\"name\":\"rustc-std-workspace-core\",\"optional\":true,\"req\":\"^1.0.1\"}],\"features\":{\"align\":[],\"const-extern-fn\":[],\"default\":[\"std\"],\"extra_traits\":[],\"rustc-dep-of-std\":[\"align\",\"rustc-std-workspace-core\"],\"std\":[],\"use_std\":[\"std\"]}}", "libc_0.2.186": "{\"dependencies\":[{\"name\":\"rustc-std-workspace-core\",\"optional\":true,\"req\":\"^1.0.1\"}],\"features\":{\"align\":[],\"const-extern-fn\":[],\"default\":[\"std\"],\"extra_traits\":[],\"rustc-dep-of-std\":[\"align\",\"rustc-std-workspace-core\"],\"std\":[],\"use_std\":[\"std\"]}}", @@ -1051,7 +961,6 @@ "lock_api_0.4.14": "{\"dependencies\":[{\"name\":\"owning_ref\",\"optional\":true,\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"scopeguard\",\"req\":\"^1.1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.126\"}],\"features\":{\"arc_lock\":[],\"atomic_usize\":[],\"default\":[\"atomic_usize\"],\"nightly\":[]}}", "log_0.4.29": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.63\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval\",\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval_derive\",\"req\":\"^2.16\"},{\"default_features\":false,\"name\":\"sval_ref\",\"optional\":true,\"req\":\"^2.16\"},{\"default_features\":false,\"features\":[\"inline-i128\"],\"name\":\"value-bag\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"test\"],\"kind\":\"dev\",\"name\":\"value-bag\",\"req\":\"^1.12\"}],\"features\":{\"kv\":[],\"kv_serde\":[\"kv_std\",\"value-bag/serde\",\"serde\"],\"kv_std\":[\"std\",\"kv\",\"value-bag/error\"],\"kv_sval\":[\"kv\",\"value-bag/sval\",\"sval\",\"sval_ref\"],\"kv_unstable\":[\"kv\",\"value-bag\"],\"kv_unstable_serde\":[\"kv_serde\",\"kv_unstable_std\"],\"kv_unstable_std\":[\"kv_std\",\"kv_unstable\"],\"kv_unstable_sval\":[\"kv_sval\",\"kv_unstable\"],\"max_level_debug\":[],\"max_level_error\":[],\"max_level_info\":[],\"max_level_off\":[],\"max_level_trace\":[],\"max_level_warn\":[],\"release_max_level_debug\":[],\"release_max_level_error\":[],\"release_max_level_info\":[],\"release_max_level_off\":[],\"release_max_level_trace\":[],\"release_max_level_warn\":[],\"serde\":[\"serde_core\"],\"std\":[]}}", "log_0.4.30": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.63\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval\",\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval_derive\",\"req\":\"^2.16\"},{\"default_features\":false,\"name\":\"sval_ref\",\"optional\":true,\"req\":\"^2.16\"},{\"default_features\":false,\"features\":[\"inline-i128\"],\"name\":\"value-bag\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"test\"],\"kind\":\"dev\",\"name\":\"value-bag\",\"req\":\"^1.12\"}],\"features\":{\"kv\":[],\"kv_serde\":[\"kv_std\",\"value-bag/serde\",\"serde\"],\"kv_std\":[\"std\",\"kv\",\"value-bag/error\"],\"kv_sval\":[\"kv\",\"value-bag/sval\",\"sval\",\"sval_ref\"],\"kv_unstable\":[\"kv\",\"value-bag\"],\"kv_unstable_serde\":[\"kv_serde\",\"kv_unstable_std\"],\"kv_unstable_std\":[\"kv_std\",\"kv_unstable\"],\"kv_unstable_sval\":[\"kv_sval\",\"kv_unstable\"],\"max_level_debug\":[],\"max_level_error\":[],\"max_level_info\":[],\"max_level_off\":[],\"max_level_trace\":[],\"max_level_warn\":[],\"release_max_level_debug\":[],\"release_max_level_error\":[],\"release_max_level_info\":[],\"release_max_level_off\":[],\"release_max_level_trace\":[],\"release_max_level_warn\":[],\"serde\":[\"serde_core\"],\"std\":[]}}", - "lru-slab_0.1.2": "{\"dependencies\":[],\"features\":{}}", "lru_0.16.3": "{\"dependencies\":[{\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.16.0\"},{\"kind\":\"dev\",\"name\":\"scoped_threadpool\",\"req\":\"0.1.*\"},{\"kind\":\"dev\",\"name\":\"stats_alloc\",\"req\":\"0.1.*\"}],\"features\":{\"default\":[\"hashbrown\"],\"nightly\":[\"hashbrown\",\"hashbrown/nightly\"]}}", "lz4_flex_0.11.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"binggan\",\"req\":\"^0.12.0\"},{\"kind\":\"dev\",\"name\":\"jemallocator\",\"req\":\"^0.5.4\"},{\"kind\":\"dev\",\"name\":\"lz4-compress\",\"req\":\"^0.1.1\"},{\"kind\":\"dev\",\"name\":\"lzzzz\",\"req\":\"^1.0.4\"},{\"kind\":\"dev\",\"name\":\"more-asserts\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.91\"},{\"kind\":\"dev\",\"name\":\"snap\",\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"xxhash32\"],\"name\":\"twox-hash\",\"optional\":true,\"req\":\"^2.0.0\"}],\"features\":{\"checked-decode\":[],\"default\":[\"std\",\"safe-encode\",\"safe-decode\",\"frame\",\"checked-decode\"],\"frame\":[\"std\",\"dep:twox-hash\"],\"nightly\":[],\"safe-decode\":[],\"safe-encode\":[],\"std\":[]}}", "macro_magic_0.5.1": "{\"dependencies\":[{\"name\":\"macro_magic_core\",\"optional\":true,\"req\":\"^0.5.1\"},{\"name\":\"macro_magic_macros\",\"req\":\"^0.5.1\"},{\"name\":\"quote\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"}],\"features\":{\"default\":[],\"proc_support\":[\"dep:macro_magic_core\",\"dep:syn\",\"dep:quote\"]}}", @@ -1063,11 +972,12 @@ "md-5_0.10.6": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"},{\"name\":\"md5-asm\",\"optional\":true,\"req\":\"^0.5\",\"target\":\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"}],\"features\":{\"asm\":[\"md5-asm\"],\"default\":[\"std\"],\"force-soft\":[],\"loongarch64_asm\":[],\"oid\":[\"digest/oid\"],\"std\":[\"digest/std\"]}}", "memchr_2.8.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"libc\":[],\"logging\":[\"dep:log\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[\"alloc\"],\"use_std\":[\"std\"]}}", "memchr_2.8.1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"libc\":[],\"logging\":[\"dep:log\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[\"alloc\"],\"use_std\":[\"std\"]}}", - "memmap2_0.9.9": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.151\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"owning_ref\",\"req\":\"^0.4.1\"},{\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{}}", + "memmap2_0.9.11": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.151\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"owning_ref\",\"req\":\"^0.4.1\"},{\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{}}", "memory-stats_1.2.0": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\"))\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_System\",\"Win32_System_ProcessStatus\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\"^0.52\",\"target\":\"cfg(target_os = \\\"windows\\\")\"}],\"features\":{\"always_use_statm\":[]}}", "mimalloc_0.1.48": "{\"dependencies\":[{\"default_features\":false,\"name\":\"libmimalloc-sys\",\"req\":\"^0.1.44\"}],\"features\":{\"debug\":[\"libmimalloc-sys/debug\"],\"debug_in_debug\":[\"libmimalloc-sys/debug_in_debug\"],\"default\":[],\"extended\":[\"libmimalloc-sys/extended\"],\"local_dynamic_tls\":[\"libmimalloc-sys/local_dynamic_tls\"],\"no_thp\":[\"libmimalloc-sys/no_thp\"],\"override\":[\"libmimalloc-sys/override\"],\"secure\":[\"libmimalloc-sys/secure\"],\"v3\":[\"libmimalloc-sys/v3\"]}}", "mime_0.3.17": "{\"dependencies\":[],\"features\":{}}", "mime_guess_2.0.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"name\":\"mime\",\"req\":\"^0.3\"},{\"name\":\"unicase\",\"req\":\"^2.4.0\"},{\"kind\":\"build\",\"name\":\"unicase\",\"req\":\"^2.4.0\"}],\"features\":{\"default\":[\"rev-mappings\"],\"rev-mappings\":[]}}", + "minicov_0.3.8": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.77\"},{\"kind\":\"build\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"]}}", "minimal-lexical_0.2.1": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"compact\":[],\"default\":[\"std\"],\"lint\":[],\"nightly\":[],\"std\":[]}}", "miniz_oxide_0.8.9": "{\"dependencies\":[{\"default_features\":false,\"name\":\"adler2\",\"req\":\"^2.0\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"simd-adler32\",\"optional\":true,\"req\":\"^0.3.3\"}],\"features\":{\"block-boundary\":[],\"default\":[\"with-alloc\"],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"adler2/rustc-dep-of-std\"],\"simd\":[\"simd-adler32\"],\"std\":[],\"with-alloc\":[]}}", "mio_1.1.1": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"libc\",\"req\":\"^0.2.178\",\"target\":\"cfg(target_os = \\\"hermit\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.178\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.178\",\"target\":\"cfg(unix)\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"name\":\"wasi\",\"req\":\"^0.11.0\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"features\":[\"Wdk_Foundation\",\"Wdk_Storage_FileSystem\",\"Wdk_System_IO\",\"Win32_Foundation\",\"Win32_Networking_WinSock\",\"Win32_Storage_FileSystem\",\"Win32_Security\",\"Win32_System_IO\",\"Win32_System_WindowsProgramming\"],\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"log\"],\"net\":[],\"os-ext\":[\"os-poll\",\"windows-sys/Win32_System_Pipes\",\"windows-sys/Win32_Security\"],\"os-poll\":[]}}", @@ -1079,26 +989,30 @@ "mongodb-internal-macros_3.3.0": "{\"dependencies\":[{\"features\":[\"proc_support\"],\"name\":\"macro_magic\",\"req\":\"^0.5.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.78\"},{\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"features\":[\"full\",\"parsing\",\"proc-macro\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.52\"}],\"features\":{}}", "mongodb_3.3.0": "{\"dependencies\":[{\"features\":[\"backtrace\"],\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"approx\",\"req\":\"^0.5.1\"},{\"name\":\"async-trait\",\"req\":\"^0.1.42\"},{\"default_features\":false,\"features\":[\"default-https-client\",\"rt-tokio\"],\"name\":\"aws-config\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"aws-credential-types\",\"optional\":true,\"req\":\"^1.2.4\"},{\"default_features\":false,\"features\":[\"sign-http\"],\"name\":\"aws-sigv4\",\"optional\":true,\"req\":\"^1.3.3\"},{\"default_features\":false,\"name\":\"aws-types\",\"optional\":true,\"req\":\"^1.3.7\"},{\"kind\":\"dev\",\"name\":\"backtrace\",\"req\":\"^0.3.68\"},{\"name\":\"base64\",\"req\":\"^0.13.0\"},{\"name\":\"bitflags\",\"req\":\"^1.1.0\"},{\"name\":\"bson2\",\"optional\":true,\"package\":\"bson\",\"req\":\"^2.15.0\"},{\"features\":[\"serde\"],\"name\":\"bson3\",\"optional\":true,\"package\":\"bson\",\"req\":\"^3.0.0\"},{\"features\":[\"serde\",\"serde_json-1\"],\"kind\":\"dev\",\"name\":\"bson3\",\"package\":\"bson\",\"req\":\"^3.0.0\"},{\"default_features\":false,\"features\":[\"clock\",\"std\"],\"name\":\"chrono\",\"req\":\"^0.4.7\"},{\"default_features\":false,\"name\":\"cross-krb5\",\"optional\":true,\"req\":\"^0.4.2\",\"target\":\"cfg(not(windows))\"},{\"kind\":\"dev\",\"name\":\"ctrlc\",\"req\":\"^3.2.2\"},{\"name\":\"derive-where\",\"req\":\"^1.2.7\"},{\"name\":\"derive_more\",\"req\":\"^0.99.17\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"function_name\",\"req\":\"^0.2.1\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"futures-core\",\"req\":\"^0.3.14\"},{\"name\":\"futures-executor\",\"req\":\"^0.3.14\"},{\"name\":\"futures-io\",\"req\":\"^0.3.21\"},{\"features\":[\"io\"],\"name\":\"futures-util\",\"req\":\"^0.3.14\"},{\"name\":\"hex\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"hickory-proto\",\"optional\":true,\"req\":\"^0.24.2\"},{\"name\":\"hickory-resolver\",\"optional\":true,\"req\":\"^0.24.2\"},{\"name\":\"hmac\",\"req\":\"^0.12.1\"},{\"kind\":\"dev\",\"name\":\"home\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"http\",\"optional\":true,\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"lambda_runtime\",\"req\":\"^0.6.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"name\":\"macro_magic\",\"req\":\"^0.5.1\"},{\"name\":\"md-5\",\"req\":\"^0.10.1\"},{\"default_features\":false,\"name\":\"mongocrypt\",\"optional\":true,\"req\":\"^0.3.1\"},{\"name\":\"mongodb-internal-macros\",\"req\":\"^3.3.0\"},{\"name\":\"num_cpus\",\"optional\":true,\"req\":\"^1.13.1\"},{\"name\":\"once_cell\",\"req\":\"^1.19.0\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.38\"},{\"name\":\"openssl-probe\",\"optional\":true,\"req\":\"^0.1.5\"},{\"default_features\":false,\"name\":\"pbkdf2\",\"req\":\"^0.11.0\"},{\"name\":\"pem\",\"optional\":true,\"req\":\"^3.0.4\"},{\"name\":\"percent-encoding\",\"req\":\"^2.0.0\"},{\"features\":[\"encryption\",\"pkcs5\"],\"name\":\"pkcs8\",\"optional\":true,\"req\":\"^0.10.2\"},{\"features\":[\"3des\",\"des-insecure\",\"sha1-insecure\"],\"kind\":\"dev\",\"name\":\"pkcs8\",\"req\":\"^0.10.2\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.3.0\"},{\"features\":[\"small_rng\"],\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.5.3\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.6.0\"},{\"default_features\":false,\"features\":[\"json\",\"rustls-tls\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12.12\"},{\"features\":[\"rustls-tls\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12.2\"},{\"name\":\"rustc_version_runtime\",\"req\":\"^0.3.0\"},{\"default_features\":false,\"features\":[\"logging\",\"ring\",\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.20\"},{\"name\":\"rustversion\",\"req\":\"^1.0.20\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.125\"},{\"features\":[\"rc\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\">=0.0.0\"},{\"kind\":\"dev\",\"name\":\"serde-hex\",\"req\":\"^0.1.0\"},{\"name\":\"serde_bytes\",\"req\":\"^0.11.5\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.64\"},{\"kind\":\"dev\",\"name\":\"serde_path_to_error\",\"req\":\"^0.1\"},{\"name\":\"serde_with\",\"req\":\"^3.8.1\"},{\"name\":\"sha1\",\"req\":\"^0.10.0\"},{\"name\":\"sha2\",\"req\":\"^0.10.2\"},{\"name\":\"snap\",\"optional\":true,\"req\":\"^1.0.5\"},{\"name\":\"socket2\",\"req\":\"^0.5.5\"},{\"name\":\"stringprep\",\"req\":\"^0.1.2\"},{\"name\":\"strsim\",\"req\":\"^0.11.1\"},{\"name\":\"take_mut\",\"req\":\"^0.2.2\"},{\"name\":\"thiserror\",\"req\":\"^1.0.24\"},{\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.9\"},{\"features\":[\"io-util\",\"sync\",\"macros\",\"net\",\"process\",\"rt\",\"time\",\"fs\"],\"name\":\"tokio\",\"req\":\"^1.17.0\"},{\"features\":[\"fs\",\"parking_lot\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\">=0.0.0\"},{\"name\":\"tokio-openssl\",\"optional\":true,\"req\":\"^0.6.3\"},{\"default_features\":false,\"features\":[\"logging\",\"ring\",\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26\"},{\"features\":[\"io\",\"compat\"],\"name\":\"tokio-util\",\"req\":\"^0.7.0\"},{\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.16\"},{\"name\":\"typed-builder\",\"req\":\"^0.20.0\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"req\":\"^1.1.2\"},{\"name\":\"webpki-roots\",\"req\":\"^0.26\"},{\"features\":[\"Win32_Security_Authentication_Identity\",\"Win32_Security_Credentials\",\"Win32_Foundation\",\"Win32_System\",\"Win32_System_Rpc\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\"^0.60\",\"target\":\"cfg(windows)\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.11.2\"}],\"features\":{\"aws-auth\":[\"dep:aws-config\",\"dep:aws-types\",\"dep:aws-credential-types\",\"dep:aws-sigv4\",\"dep:http\"],\"azure-kms\":[\"dep:reqwest\"],\"azure-oidc\":[\"dep:reqwest\"],\"bson-2\":[\"dep:bson2\",\"mongocrypt/bson-2\"],\"bson-3\":[\"dep:bson3\",\"mongocrypt/bson-3\"],\"cert-key-password\":[\"dep:pem\",\"dep:pkcs8\"],\"compat-3-0-0\":[\"compat-3-3-0\",\"bson-2\"],\"compat-3-3-0\":[],\"default\":[\"compat-3-0-0\",\"rustls-tls\",\"dns-resolver\"],\"dns-resolver\":[\"dep:hickory-resolver\",\"dep:hickory-proto\"],\"gcp-kms\":[\"dep:reqwest\"],\"gcp-oidc\":[\"dep:reqwest\"],\"gssapi-auth\":[\"dep:cross-krb5\",\"dep:windows-sys\",\"dns-resolver\"],\"in-use-encryption\":[\"dep:mongocrypt\",\"dep:rayon\",\"dep:num_cpus\"],\"in-use-encryption-unstable\":[\"in-use-encryption\"],\"openssl-tls\":[\"dep:openssl\",\"dep:openssl-probe\",\"dep:tokio-openssl\"],\"rustls-tls\":[\"dep:rustls\",\"dep:tokio-rustls\"],\"snappy-compression\":[\"dep:snap\"],\"sync\":[],\"tracing-unstable\":[\"dep:tracing\",\"dep:log\",\"bson3?/serde_json-1\"],\"zlib-compression\":[\"dep:flate2\"],\"zstd-compression\":[\"dep:zstd\"]}}", "multimap_0.10.1": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"serde_impl\"],\"serde_impl\":[\"serde\"]}}", + "multipart_0.18.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"buf_redux\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"clippy\",\"optional\":true,\"req\":\">=0.0, <0.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.5\"},{\"name\":\"httparse\",\"optional\":true,\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"hyper\",\"optional\":true,\"req\":\">=0.9, <0.11\"},{\"name\":\"iron\",\"optional\":true,\"req\":\">=0.4, <0.7\"},{\"name\":\"lazy_static\",\"optional\":true,\"req\":\"^1.2.0\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"mime\",\"req\":\"^0.3.14\"},{\"name\":\"mime_guess\",\"req\":\"^2.0.1\"},{\"name\":\"nickel\",\"optional\":true,\"req\":\">=0.10.1\"},{\"name\":\"quick-error\",\"optional\":true,\"req\":\"^1.2\"},{\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"rocket\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"safemem\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"tempfile\",\"req\":\"^3\"},{\"name\":\"tiny_http\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"twoway\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{\"bench\":[],\"client\":[],\"default\":[\"client\",\"hyper\",\"iron\",\"mock\",\"nickel\",\"server\",\"tiny_http\"],\"mock\":[],\"nightly\":[],\"server\":[\"buf_redux\",\"httparse\",\"quick-error\",\"safemem\",\"twoway\"]}}", "ndk-context_0.1.1": "{\"dependencies\":[],\"features\":{}}", "nom_7.1.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.3\"},{\"default_features\":false,\"name\":\"minimal-lexical\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"docsrs\":[],\"std\":[\"alloc\",\"memchr/std\",\"minimal-lexical/std\"]}}", "nu-ansi-term_0.50.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.3\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.152\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.94\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Console\",\"Win32_Storage_FileSystem\",\"Win32_Security\"],\"name\":\"windows\",\"package\":\"windows-sys\",\"req\":\">=0.59, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"std\"],\"derive_serde_style\":[\"serde\"],\"gnu_legacy\":[],\"std\":[]}}", "num-bigint-dig_0.8.6": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"spin_no_std\"],\"name\":\"lazy_static\",\"req\":\"^1.2.0\"},{\"name\":\"libm\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-integer\",\"req\":\"^0.1.39\"},{\"default_features\":false,\"name\":\"num-iter\",\"req\":\"^0.1.37\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.4\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8.3\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand_chacha\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rand_isaac\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"smallvec\",\"req\":\"^1.10.0\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.5\"}],\"features\":{\"default\":[\"std\",\"u64_digit\"],\"fuzz\":[\"arbitrary\",\"smallvec/arbitrary\"],\"i128\":[],\"nightly\":[],\"prime\":[\"rand/std_rng\"],\"std\":[\"num-integer/std\",\"num-traits/std\",\"smallvec/write\",\"rand/std\",\"serde/std\"],\"u64_digit\":[]}}", "num-bigint_0.4.6": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-integer\",\"req\":\"^0.1.46\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.18\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\"],\"quickcheck\":[\"dep:quickcheck\"],\"rand\":[\"dep:rand\"],\"serde\":[\"dep:serde\"],\"std\":[\"num-integer/std\",\"num-traits/std\"]}}", + "num-conv_0.2.1": "{\"dependencies\":[],\"features\":{}}", "num-conv_0.2.2": "{\"dependencies\":[],\"features\":{}}", "num-integer_0.1.46": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.11\"}],\"features\":{\"default\":[\"std\"],\"i128\":[],\"std\":[\"num-traits/std\"]}}", "num-iter_0.1.45": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-integer\",\"req\":\"^0.1.46\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.11\"}],\"features\":{\"default\":[\"std\"],\"i128\":[],\"std\":[\"num-integer/std\",\"num-traits/std\"]}}", "num-rational_0.4.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"num-bigint\",\"optional\":true,\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-integer\",\"req\":\"^0.1.42\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.18\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.0\"}],\"features\":{\"default\":[\"num-bigint\",\"std\"],\"num-bigint\":[\"dep:num-bigint\"],\"num-bigint-std\":[\"num-bigint/std\"],\"serde\":[\"dep:serde\"],\"std\":[\"num-bigint?/std\",\"num-integer/std\",\"num-traits/std\"]}}", "num-traits_0.2.19": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"name\":\"libm\",\"optional\":true,\"req\":\"^0.2.0\"}],\"features\":{\"default\":[\"std\"],\"i128\":[],\"libm\":[\"dep:libm\"],\"std\":[]}}", + "num_cpus_1.17.0": "{\"dependencies\":[{\"name\":\"hermit-abi\",\"req\":\"^0.5.0\",\"target\":\"cfg(target_os = \\\"hermit\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.26\",\"target\":\"cfg(not(windows))\"}],\"features\":{}}", + "num_threads_0.1.7": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.107\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\"))\"}],\"features\":{}}", "once_cell_1.21.4": "{\"dependencies\":[{\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1.1.3\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"critical-section\",\"req\":\"^1.1.3\"},{\"default_features\":false,\"name\":\"parking_lot_core\",\"optional\":true,\"req\":\"^0.9.10\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.10.6\"}],\"features\":{\"alloc\":[\"race\"],\"atomic-polyfill\":[\"critical-section\"],\"critical-section\":[\"dep:critical-section\",\"portable-atomic\"],\"default\":[\"std\"],\"parking_lot\":[\"dep:parking_lot_core\"],\"portable-atomic\":[\"dep:portable-atomic\"],\"race\":[],\"std\":[\"alloc\"],\"unstable\":[]}}", "once_cell_polyfill_1.70.2": "{\"dependencies\":[],\"features\":{\"default\":[]}}", "openssl-probe_0.1.6": "{\"dependencies\":[],\"features\":{}}", - "opentelemetry-appender-tracing_0.30.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"features\":[\"logs\"],\"name\":\"opentelemetry\",\"req\":\"^0.30\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.14\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"default_features\":false,\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\">=0.1.40\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\">=0.1.40\"},{\"default_features\":false,\"name\":\"tracing-core\",\"req\":\">=0.1.33\"},{\"name\":\"tracing-log\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"tracing-log\",\"req\":\"^0.2\"},{\"name\":\"tracing-opentelemetry\",\"optional\":true,\"req\":\"^0.31\"},{\"default_features\":false,\"features\":[\"registry\",\"std\"],\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"env-filter\",\"registry\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"}],\"features\":{\"default\":[],\"experimental_metadata_attributes\":[\"dep:tracing-log\"],\"experimental_use_tracing_span_context\":[\"tracing-opentelemetry\"],\"spec_unstable_logs_enabled\":[\"opentelemetry/spec_unstable_logs_enabled\"]}}", - "opentelemetry-http_0.30.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"req\":\"^1.1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.3\"},{\"features\":[\"client-legacy\",\"http1\",\"http2\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1\"},{\"features\":[\"trace\"],\"name\":\"opentelemetry\",\"req\":\"^0.30\"},{\"default_features\":false,\"features\":[\"blocking\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"default\":[\"internal-logs\"],\"hyper\":[\"dep:http-body-util\",\"dep:hyper\",\"dep:hyper-util\",\"dep:tokio\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"reqwest-rustls\":[\"reqwest\",\"reqwest/rustls-tls-native-roots\"],\"reqwest-rustls-webpki-roots\":[\"reqwest\",\"reqwest/rustls-tls-webpki-roots\"]}}", - "opentelemetry-otlp_0.30.0": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"default_features\":false,\"name\":\"opentelemetry\",\"req\":\"^0.30\"},{\"name\":\"opentelemetry-http\",\"optional\":true,\"req\":\"^0.30\"},{\"default_features\":false,\"name\":\"opentelemetry-proto\",\"req\":\"^0.30\"},{\"default_features\":false,\"name\":\"opentelemetry_sdk\",\"req\":\"^0.30\"},{\"name\":\"prost\",\"optional\":true,\"req\":\"^0.13\"},{\"default_features\":false,\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"sync\",\"rt\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"net\"],\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"tonic\",\"optional\":true,\"req\":\"^0.13\"},{\"default_features\":false,\"features\":[\"router\",\"server\"],\"kind\":\"dev\",\"name\":\"tonic\",\"req\":\"^0.13\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\">=0.1.40\"}],\"features\":{\"default\":[\"http-proto\",\"reqwest-blocking-client\",\"trace\",\"metrics\",\"logs\",\"internal-logs\"],\"grpc-tonic\":[\"tonic\",\"prost\",\"http\",\"tokio\",\"opentelemetry-proto/gen-tonic\"],\"gzip-tonic\":[\"tonic/gzip\"],\"http-json\":[\"serde_json\",\"prost\",\"opentelemetry-http\",\"opentelemetry-proto/gen-tonic-messages\",\"opentelemetry-proto/with-serde\",\"http\",\"trace\",\"metrics\"],\"http-proto\":[\"prost\",\"opentelemetry-http\",\"opentelemetry-proto/gen-tonic-messages\",\"http\",\"trace\",\"metrics\"],\"hyper-client\":[\"opentelemetry-http/hyper\"],\"integration-testing\":[\"tonic\",\"prost\",\"tokio/full\",\"trace\",\"logs\"],\"internal-logs\":[\"tracing\",\"opentelemetry/internal-logs\"],\"logs\":[\"opentelemetry/logs\",\"opentelemetry_sdk/logs\",\"opentelemetry-proto/logs\"],\"metrics\":[\"opentelemetry/metrics\",\"opentelemetry_sdk/metrics\",\"opentelemetry-proto/metrics\"],\"reqwest-blocking-client\":[\"reqwest/blocking\",\"opentelemetry-http/reqwest\"],\"reqwest-client\":[\"reqwest\",\"opentelemetry-http/reqwest\"],\"reqwest-rustls\":[\"reqwest\",\"opentelemetry-http/reqwest-rustls\"],\"reqwest-rustls-webpki-roots\":[\"reqwest\",\"opentelemetry-http/reqwest-rustls-webpki-roots\"],\"serialize\":[\"serde\",\"serde_json\"],\"tls\":[\"tonic/tls-ring\"],\"tls-roots\":[\"tls\",\"tonic/tls-native-roots\"],\"tls-webpki-roots\":[\"tls\",\"tonic/tls-webpki-roots\"],\"trace\":[\"opentelemetry/trace\",\"opentelemetry_sdk/trace\",\"opentelemetry-proto/trace\"],\"zstd-tonic\":[\"tonic/zstd\"]}}", - "opentelemetry-proto_0.30.0": "{\"dependencies\":[{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4.3\"},{\"default_features\":false,\"name\":\"opentelemetry\",\"req\":\"^0.30\"},{\"default_features\":false,\"name\":\"opentelemetry_sdk\",\"req\":\"^0.30\"},{\"name\":\"prost\",\"optional\":true,\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"prost-build\",\"req\":\"^0.13\"},{\"name\":\"schemars\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"serde_derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.3.0\"},{\"default_features\":false,\"features\":[\"codegen\",\"prost\"],\"name\":\"tonic\",\"optional\":true,\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"tonic-build\",\"req\":\"^0.13\"}],\"features\":{\"default\":[\"full\"],\"full\":[\"gen-tonic\",\"trace\",\"logs\",\"metrics\",\"zpages\",\"with-serde\",\"internal-logs\"],\"gen-tonic\":[\"gen-tonic-messages\",\"tonic/channel\"],\"gen-tonic-messages\":[\"tonic\",\"prost\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"logs\":[\"opentelemetry/logs\",\"opentelemetry_sdk/logs\"],\"metrics\":[\"opentelemetry/metrics\",\"opentelemetry_sdk/metrics\"],\"profiles\":[],\"testing\":[\"opentelemetry/testing\"],\"trace\":[\"opentelemetry/trace\",\"opentelemetry_sdk/trace\"],\"with-schemars\":[\"schemars\"],\"with-serde\":[\"serde\",\"hex\",\"base64\"],\"zpages\":[\"trace\"]}}", - "opentelemetry-semantic-conventions_0.30.0": "{\"dependencies\":[],\"features\":{\"default\":[],\"semconv_experimental\":[]}}", - "opentelemetry_0.30.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"futures-sink\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"js-sys\",\"req\":\"^0.3.63\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"os_rng\",\"thread_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\">=0.1.40\"}],\"features\":{\"default\":[\"trace\",\"metrics\",\"logs\",\"internal-logs\",\"futures\"],\"futures\":[\"futures-core\",\"futures-sink\",\"pin-project-lite\"],\"internal-logs\":[\"tracing\"],\"logs\":[],\"metrics\":[],\"spec_unstable_logs_enabled\":[\"logs\"],\"testing\":[\"trace\"],\"trace\":[\"futures\",\"thiserror\"]}}", - "opentelemetry_sdk_0.30.0": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"futures-channel\",\"req\":\"^0.3\"},{\"name\":\"futures-executor\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\",\"sink\",\"async-await-macro\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"name\":\"opentelemetry\",\"req\":\"^0.30\"},{\"name\":\"opentelemetry-http\",\"optional\":true,\"req\":\"^0.30\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.0\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.14\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"default_features\":false,\"features\":[\"std\",\"std_rng\",\"small_rng\",\"os_rng\",\"thread_rng\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.23.0\"},{\"default_features\":false,\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"rt\",\"time\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"url\",\"optional\":true,\"req\":\"^2.5\"}],\"features\":{\"default\":[\"trace\",\"metrics\",\"logs\",\"internal-logs\"],\"experimental_async_runtime\":[],\"experimental_logs_batch_log_processor_with_async_runtime\":[\"logs\",\"experimental_async_runtime\"],\"experimental_logs_concurrent_log_processor\":[\"logs\"],\"experimental_metrics_custom_reader\":[\"metrics\"],\"experimental_metrics_disable_name_validation\":[\"metrics\"],\"experimental_metrics_periodicreader_with_async_runtime\":[\"metrics\",\"experimental_async_runtime\"],\"experimental_trace_batch_span_processor_with_async_runtime\":[\"trace\",\"experimental_async_runtime\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"jaeger_remote_sampler\":[\"trace\",\"opentelemetry-http\",\"http\",\"serde\",\"serde_json\",\"url\",\"experimental_async_runtime\"],\"logs\":[\"opentelemetry/logs\",\"serde_json\"],\"metrics\":[\"opentelemetry/metrics\"],\"rt-tokio\":[\"tokio\",\"tokio-stream\",\"experimental_async_runtime\"],\"rt-tokio-current-thread\":[\"tokio\",\"tokio-stream\",\"experimental_async_runtime\"],\"spec_unstable_logs_enabled\":[\"logs\",\"opentelemetry/spec_unstable_logs_enabled\"],\"spec_unstable_metrics_views\":[\"metrics\"],\"testing\":[\"opentelemetry/testing\",\"trace\",\"metrics\",\"logs\",\"rt-tokio\",\"rt-tokio-current-thread\",\"tokio/macros\",\"tokio/rt-multi-thread\"],\"trace\":[\"opentelemetry/trace\",\"rand\",\"percent-encoding\"]}}", + "opentelemetry-appender-tracing_0.32.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"features\":[\"logs\"],\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"features\":[\"logs\",\"testing\",\"internal-logs\"],\"kind\":\"dev\",\"name\":\"opentelemetry_sdk\",\"req\":\"^0.32\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.14\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\">=0.1.40\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\">=0.1.40\"},{\"default_features\":false,\"name\":\"tracing-core\",\"req\":\">=0.1.33\"},{\"name\":\"tracing-log\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"tracing-log\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"registry\",\"std\"],\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"env-filter\",\"registry\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"}],\"features\":{\"bench_profiling\":[],\"default\":[],\"experimental_metadata_attributes\":[\"dep:tracing-log\"],\"experimental_span_attributes\":[]}}", + "opentelemetry-http_0.32.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"req\":\"^1.1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.3\"},{\"features\":[\"client-legacy\",\"http1\",\"http2\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"trace\"],\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.13.1\"},{\"default_features\":false,\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"default\":[\"internal-logs\"],\"hyper\":[\"dep:http-body-util\",\"dep:hyper\",\"dep:hyper-util\",\"dep:tokio\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"reqwest\":[\"dep:reqwest\"],\"reqwest-blocking\":[\"dep:reqwest\",\"reqwest/blocking\"],\"reqwest-rustls\":[\"dep:reqwest\",\"reqwest/default-tls\"],\"reqwest-rustls-webpki-roots\":[\"dep:reqwest\",\"reqwest/default-tls\",\"reqwest/webpki-roots\"]}}", + "opentelemetry-otlp_0.32.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.1.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"name\":\"httpdate\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"name\":\"opentelemetry-http\",\"optional\":true,\"req\":\"^0.32\"},{\"default_features\":false,\"name\":\"opentelemetry-proto\",\"req\":\"^0.32\"},{\"default_features\":false,\"name\":\"opentelemetry_sdk\",\"req\":\"^0.32\"},{\"default_features\":false,\"features\":[\"trace\",\"testing\"],\"kind\":\"dev\",\"name\":\"opentelemetry_sdk\",\"req\":\"^0.32\"},{\"name\":\"prost\",\"optional\":true,\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.13.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"sync\",\"rt\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"net\"],\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"tonic\",\"optional\":true,\"req\":\"^0.14.1\"},{\"default_features\":false,\"features\":[\"router\",\"server\"],\"kind\":\"dev\",\"name\":\"tonic\",\"req\":\"^0.14.1\"},{\"name\":\"tonic-types\",\"optional\":true,\"req\":\"^0.14.1\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13\"}],\"features\":{\"default\":[\"http-proto\",\"reqwest-blocking-client\",\"trace\",\"metrics\",\"logs\",\"internal-logs\"],\"experimental-grpc-retry\":[\"grpc-tonic\",\"opentelemetry_sdk/experimental_async_runtime\",\"opentelemetry_sdk/rt-tokio\"],\"experimental-http-retry\":[\"opentelemetry_sdk/experimental_async_runtime\",\"opentelemetry_sdk/rt-tokio\",\"tokio\",\"httpdate\"],\"grpc-tonic\":[\"tonic\",\"tonic-types\",\"prost\",\"http\",\"tokio\",\"opentelemetry-proto/gen-tonic\"],\"gzip-http\":[\"flate2\"],\"gzip-tonic\":[\"tonic/gzip\"],\"http-json\":[\"serde_json\",\"prost\",\"opentelemetry-http\",\"opentelemetry-proto/gen-tonic-messages\",\"opentelemetry-proto/with-serde\",\"http\",\"trace\",\"metrics\"],\"http-proto\":[\"prost\",\"opentelemetry-http\",\"opentelemetry-proto/gen-tonic-messages\",\"http\",\"trace\",\"metrics\"],\"hyper-client\":[\"opentelemetry-http/hyper\"],\"integration-testing\":[\"tonic\",\"prost\",\"tokio/full\",\"trace\",\"logs\"],\"internal-logs\":[\"opentelemetry_sdk/internal-logs\",\"opentelemetry/internal-logs\"],\"logs\":[\"opentelemetry/logs\",\"opentelemetry_sdk/logs\",\"opentelemetry-proto/logs\"],\"metrics\":[\"opentelemetry/metrics\",\"opentelemetry_sdk/metrics\",\"opentelemetry-proto/metrics\"],\"reqwest-blocking-client\":[\"reqwest/blocking\",\"opentelemetry-http/reqwest-blocking\"],\"reqwest-client\":[\"reqwest\",\"opentelemetry-http/reqwest\"],\"reqwest-rustls\":[\"reqwest\",\"opentelemetry-http/reqwest-rustls\"],\"reqwest-rustls-webpki-roots\":[\"reqwest\",\"opentelemetry-http/reqwest-rustls-webpki-roots\"],\"serialize\":[\"serde\",\"serde_json\"],\"tls\":[\"tls-ring\"],\"tls-aws-lc\":[\"tonic/tls-aws-lc\"],\"tls-provider-agnostic\":[\"tonic/_tls-any\"],\"tls-ring\":[\"tonic/tls-ring\"],\"tls-roots\":[\"tonic/tls-native-roots\"],\"tls-webpki-roots\":[\"tonic/tls-webpki-roots\"],\"trace\":[\"opentelemetry/trace\",\"opentelemetry_sdk/trace\",\"opentelemetry-proto/trace\"],\"zstd-http\":[\"zstd\"],\"zstd-tonic\":[\"tonic/zstd\"]}}", + "opentelemetry-proto_0.32.0": "{\"dependencies\":[{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"const-hex\",\"optional\":true,\"req\":\"^1.14.1\"},{\"default_features\":false,\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"features\":[\"testing\"],\"kind\":\"dev\",\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"name\":\"opentelemetry_sdk\",\"req\":\"^0.32\"},{\"name\":\"prost\",\"optional\":true,\"req\":\"^0.14\"},{\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde_derive\",\"std\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.3.0\"},{\"default_features\":false,\"features\":[\"codegen\"],\"name\":\"tonic\",\"optional\":true,\"req\":\"^0.14.1\"},{\"name\":\"tonic-prost\",\"optional\":true,\"req\":\"^0.14.1\"},{\"kind\":\"dev\",\"name\":\"tonic-prost-build\",\"req\":\"^0.14.1\"}],\"features\":{\"default\":[\"full\"],\"full\":[\"gen-tonic\",\"trace\",\"logs\",\"metrics\",\"zpages\",\"with-serde\",\"internal-logs\"],\"gen-tonic\":[\"gen-tonic-messages\",\"tonic\",\"tonic-prost\",\"tonic/channel\"],\"gen-tonic-messages\":[\"prost\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"logs\":[\"opentelemetry/logs\",\"opentelemetry_sdk/logs\"],\"metrics\":[\"opentelemetry/metrics\",\"opentelemetry_sdk/metrics\"],\"profiles\":[],\"testing\":[\"opentelemetry/testing\"],\"trace\":[\"opentelemetry/trace\",\"opentelemetry_sdk/trace\"],\"with-schemars\":[\"schemars\"],\"with-serde\":[\"serde\",\"const-hex\",\"base64\"],\"zpages\":[\"trace\"]}}", + "opentelemetry-semantic-conventions_0.32.1": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"features\":[\"trace\"],\"kind\":\"dev\",\"name\":\"opentelemetry_sdk\",\"req\":\"^0.32\"}],\"features\":{\"default\":[],\"semconv_experimental\":[]}}", + "opentelemetry_0.32.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"futures-sink\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"js-sys\",\"req\":\"^0.3.63\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"os_rng\",\"thread_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\">=0.1.40\"}],\"features\":{\"default\":[\"trace\",\"metrics\",\"logs\",\"internal-logs\",\"futures\"],\"experimental_metrics_bound_instruments\":[\"metrics\"],\"futures\":[\"futures-core\",\"futures-sink\",\"pin-project-lite\"],\"internal-logs\":[\"tracing\"],\"logs\":[],\"metrics\":[],\"testing\":[\"trace\"],\"trace\":[\"futures\",\"thiserror\"]}}", + "opentelemetry_sdk_0.32.1": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"futures-channel\",\"req\":\"^0.3\"},{\"name\":\"futures-executor\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\",\"sink\",\"async-await-macro\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"default_features\":false,\"name\":\"opentelemetry\",\"req\":\"^0.32\"},{\"default_features\":false,\"name\":\"opentelemetry-http\",\"optional\":true,\"req\":\"^0.32\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"fallback\"],\"name\":\"portable-atomic\",\"req\":\"^1\",\"target\":\"cfg(not(target_has_atomic = \\\"64\\\"))\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.14\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"default_features\":false,\"features\":[\"std\",\"std_rng\",\"small_rng\",\"os_rng\",\"thread_rng\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.23.0\"},{\"default_features\":false,\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"url\",\"optional\":true,\"req\":\"^2.5\"}],\"features\":{\"bench_profiling\":[],\"default\":[\"trace\",\"metrics\",\"logs\",\"internal-logs\"],\"experimental_async_runtime\":[],\"experimental_logs_batch_log_processor_with_async_runtime\":[\"logs\",\"experimental_async_runtime\"],\"experimental_metrics_bound_instruments\":[\"metrics\",\"opentelemetry/experimental_metrics_bound_instruments\"],\"experimental_metrics_custom_reader\":[\"metrics\"],\"experimental_metrics_disable_name_validation\":[\"metrics\"],\"experimental_metrics_periodicreader_with_async_runtime\":[\"metrics\",\"experimental_async_runtime\"],\"experimental_trace_batch_span_processor_with_async_runtime\":[\"tokio/sync\",\"trace\",\"experimental_async_runtime\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"jaeger_remote_sampler\":[\"trace\",\"opentelemetry-http\",\"http\",\"serde\",\"serde_json\",\"url\",\"experimental_async_runtime\"],\"logs\":[\"opentelemetry/logs\"],\"metrics\":[\"opentelemetry/metrics\"],\"rt-tokio\":[\"tokio/rt\",\"tokio/time\",\"tokio-stream\",\"experimental_async_runtime\"],\"rt-tokio-current-thread\":[\"tokio/rt\",\"tokio/time\",\"tokio-stream\",\"experimental_async_runtime\"],\"spec_unstable_metrics_views\":[\"metrics\"],\"testing\":[\"opentelemetry/testing\",\"trace\",\"metrics\",\"logs\",\"tokio/sync\"],\"trace\":[\"opentelemetry/trace\",\"rand\",\"percent-encoding\"]}}", "option-ext_0.2.0": "{\"dependencies\":[],\"features\":{}}", "outref_0.5.2": "{\"dependencies\":[],\"features\":{}}", "p256_0.13.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"blobby\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"der\"],\"name\":\"ecdsa-core\",\"optional\":true,\"package\":\"ecdsa\",\"req\":\"^0.16\"},{\"default_features\":false,\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"ecdsa-core\",\"package\":\"ecdsa\",\"req\":\"^0.16\"},{\"default_features\":false,\"features\":[\"hazmat\",\"sec1\"],\"name\":\"elliptic-curve\",\"req\":\"^0.13.1\"},{\"name\":\"hex-literal\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"name\":\"primeorder\",\"optional\":true,\"req\":\"^0.13\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"primeorder\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"features\":[\"getrandom\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"}],\"features\":{\"alloc\":[\"ecdsa-core?/alloc\",\"elliptic-curve/alloc\"],\"arithmetic\":[\"dep:primeorder\",\"elliptic-curve/arithmetic\"],\"bits\":[\"arithmetic\",\"elliptic-curve/bits\"],\"default\":[\"arithmetic\",\"ecdsa\",\"pem\",\"std\"],\"digest\":[\"ecdsa-core/digest\",\"ecdsa-core/hazmat\"],\"ecdh\":[\"arithmetic\",\"elliptic-curve/ecdh\"],\"ecdsa\":[\"arithmetic\",\"ecdsa-core/signing\",\"ecdsa-core/verifying\",\"sha256\"],\"expose-field\":[\"arithmetic\"],\"hash2curve\":[\"arithmetic\",\"elliptic-curve/hash2curve\"],\"jwk\":[\"elliptic-curve/jwk\"],\"pem\":[\"elliptic-curve/pem\",\"ecdsa-core/pem\",\"pkcs8\"],\"pkcs8\":[\"ecdsa-core?/pkcs8\",\"elliptic-curve/pkcs8\"],\"serde\":[\"ecdsa-core?/serde\",\"elliptic-curve/serde\",\"primeorder?/serde\",\"serdect\"],\"sha256\":[\"digest\",\"sha2\"],\"std\":[\"alloc\",\"ecdsa-core?/std\",\"elliptic-curve/std\"],\"test-vectors\":[\"dep:hex-literal\"],\"voprf\":[\"elliptic-curve/voprf\",\"sha2\"]}}", @@ -1106,7 +1020,6 @@ "parking_2.2.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"easy-parallel\",\"req\":\"^3.0.0\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(loom)\"}],\"features\":{}}", "parking_lot_0.12.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"name\":\"lock_api\",\"req\":\"^0.4.14\"},{\"name\":\"parking_lot_core\",\"req\":\"^0.9.12\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"}],\"features\":{\"arc_lock\":[\"lock_api/arc_lock\"],\"deadlock_detection\":[\"parking_lot_core/deadlock_detection\"],\"default\":[],\"hardware-lock-elision\":[],\"nightly\":[\"parking_lot_core/nightly\",\"lock_api/nightly\"],\"owning_ref\":[\"lock_api/owning_ref\"],\"send_guard\":[],\"serde\":[\"lock_api/serde\"]}}", "parking_lot_core_0.9.12": "{\"dependencies\":[{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.60\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.95\",\"target\":\"cfg(unix)\"},{\"name\":\"petgraph\",\"optional\":true,\"req\":\"^0.6.0\"},{\"name\":\"redox_syscall\",\"req\":\"^0.5\",\"target\":\"cfg(target_os = \\\"redox\\\")\"},{\"name\":\"smallvec\",\"req\":\"^1.6.1\"},{\"name\":\"windows-link\",\"req\":\"^0.2.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"deadlock_detection\":[\"petgraph\",\"backtrace\"],\"nightly\":[]}}", - "paste_1.0.15": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"paste-test-suite\",\"req\":\"^0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.49\"}],\"features\":{}}", "pastey_0.2.2": "{\"dependencies\":[],\"features\":{}}", "pathdiff_0.2.3": "{\"dependencies\":[{\"name\":\"camino\",\"optional\":true,\"req\":\"^1.0.5\"},{\"kind\":\"dev\",\"name\":\"cfg-if\",\"req\":\"^1.0.0\"}],\"features\":{}}", "patricia_tree_0.9.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"}],\"features\":{}}", @@ -1118,7 +1031,6 @@ "pest_derive_2.8.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"pest\",\"req\":\"^2.8.3\"},{\"default_features\":false,\"name\":\"pest_generator\",\"req\":\"^2.8.3\"}],\"features\":{\"default\":[\"std\"],\"grammar-extras\":[\"pest_generator/grammar-extras\"],\"not-bootstrap-in-src\":[\"pest_generator/not-bootstrap-in-src\"],\"std\":[\"pest/std\",\"pest_generator/std\"]}}", "pest_generator_2.8.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"pest\",\"req\":\"^2.8.3\"},{\"name\":\"pest_meta\",\"req\":\"^2.8.3\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{\"default\":[\"std\"],\"export-internal\":[],\"grammar-extras\":[\"pest_meta/grammar-extras\"],\"not-bootstrap-in-src\":[\"pest_meta/not-bootstrap-in-src\"],\"std\":[\"pest/std\"]}}", "pest_meta_2.8.3": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cargo\",\"optional\":true,\"req\":\"^0.81.0\"},{\"name\":\"pest\",\"req\":\"^2.8.3\"},{\"default_features\":false,\"kind\":\"build\",\"name\":\"sha2\",\"req\":\"^0.10\"}],\"features\":{\"default\":[],\"grammar-extras\":[],\"not-bootstrap-in-src\":[\"dep:cargo\"]}}", - "petgraph_0.7.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"ahash\",\"req\":\"^0.7.2\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"kind\":\"dev\",\"name\":\"defmac\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"name\":\"fixedbitset\",\"req\":\"^0.5.7\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"name\":\"indexmap\",\"req\":\"^2.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.12.1\"},{\"kind\":\"dev\",\"name\":\"odds\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.5.5\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.5.3\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"all\":[\"unstable\",\"quickcheck\",\"matrix_graph\",\"stable_graph\",\"graphmap\",\"rayon\"],\"default\":[\"graphmap\",\"stable_graph\",\"matrix_graph\"],\"generate\":[],\"graphmap\":[],\"matrix_graph\":[],\"rayon\":[\"dep:rayon\",\"indexmap/rayon\"],\"serde-1\":[\"serde\",\"serde_derive\"],\"stable_graph\":[],\"unstable\":[\"generate\"]}}", "petgraph_0.8.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"ahash\",\"req\":\"^0.7.2\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"kind\":\"dev\",\"name\":\"defmac\",\"req\":\"^0.2.1\"},{\"name\":\"dot-parser\",\"optional\":true,\"req\":\"^0.5.1\"},{\"name\":\"dot-parser-macros\",\"optional\":true,\"req\":\"^0.5.1\"},{\"default_features\":false,\"name\":\"fixedbitset\",\"req\":\"^0.5.7\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"req\":\"^0.15.0\"},{\"default_features\":false,\"name\":\"indexmap\",\"req\":\"^2.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.12.1\"},{\"kind\":\"dev\",\"name\":\"odds\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.5.5\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.5.3\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"all\":[\"unstable\",\"quickcheck\",\"matrix_graph\",\"stable_graph\",\"graphmap\",\"rayon\",\"dot_parser\"],\"default\":[\"std\",\"graphmap\",\"stable_graph\",\"matrix_graph\"],\"dot_parser\":[\"std\",\"dep:dot-parser\",\"dep:dot-parser-macros\"],\"generate\":[],\"graphmap\":[],\"matrix_graph\":[],\"quickcheck\":[\"std\",\"dep:quickcheck\",\"graphmap\",\"stable_graph\"],\"rayon\":[\"std\",\"dep:rayon\",\"indexmap/rayon\",\"hashbrown/rayon\"],\"serde-1\":[\"serde\",\"serde_derive\"],\"stable_graph\":[\"serde?/alloc\"],\"std\":[\"indexmap/std\"],\"unstable\":[\"generate\"]}}", "pin-project-internal_1.1.10": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1.0.25\"},{\"default_features\":false,\"features\":[\"parsing\",\"printing\",\"clone-impls\",\"proc-macro\",\"full\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.1\"}],\"features\":{}}", "pin-project-internal_1.1.11": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1.0.25\"},{\"default_features\":false,\"features\":[\"parsing\",\"printing\",\"clone-impls\",\"proc-macro\",\"full\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.1\"}],\"features\":{}}", @@ -1131,6 +1043,7 @@ "pkg-config_0.3.32": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"}],\"features\":{}}", "plain_0.2.3": "{\"dependencies\":[],\"features\":{}}", "portable-atomic-util_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"build-context\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"req\":\"^1.5.1\"}],\"features\":{\"alloc\":[],\"default\":[],\"std\":[\"alloc\"]}}", + "portable-atomic-util_0.2.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"build-context\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"req\":\"^1.5.1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.60\"}],\"features\":{\"alloc\":[],\"default\":[],\"std\":[\"alloc\"]}}", "portable-atomic_1.13.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"build-context\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"crabgrind\",\"req\":\"^0.1\",\"target\":\"cfg(valgrind)\"},{\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"crossbeam-utils\",\"req\":\"=0.8.16\"},{\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"=0.2.163\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.60\"},{\"kind\":\"dev\",\"name\":\"sptr\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Threading\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"fallback\"],\"disable-fiq\":[],\"fallback\":[],\"float\":[],\"force-amo\":[],\"require-cas\":[],\"s-mode\":[],\"std\":[],\"unsafe-assume-privileged\":[],\"unsafe-assume-single-core\":[]}}", "potential_utf_0.1.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"name\":\"writeable\",\"optional\":true,\"req\":\"^0.6.1\"},{\"default_features\":false,\"name\":\"zerovec\",\"optional\":true,\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"writeable/alloc\",\"zerovec?/alloc\"],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde_core\"],\"writeable\":[\"dep:writeable\"],\"zerovec\":[\"dep:zerovec\"]}}", "powerfmt_0.2.0": "{\"dependencies\":[{\"name\":\"powerfmt-macros\",\"optional\":true,\"req\":\"=0.1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"macros\"],\"macros\":[\"dep:powerfmt-macros\"],\"std\":[\"alloc\"]}}", @@ -1140,14 +1053,14 @@ "prettyplease_0.2.37": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"default_features\":false,\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.105\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"extra-traits\",\"parsing\",\"printing\",\"visit-mut\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.105\"}],\"features\":{\"verbatim\":[\"syn/parsing\"]}}", "primeorder_0.13.6": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"arithmetic\",\"sec1\"],\"name\":\"elliptic-curve\",\"req\":\"^0.13.7\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"}],\"features\":{\"alloc\":[\"elliptic-curve/alloc\"],\"dev\":[],\"serde\":[\"elliptic-curve/serde\",\"serdect\"],\"std\":[\"alloc\",\"elliptic-curve/std\"]}}", "proc-macro2_1.0.106": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tar\",\"req\":\"^0.4\"},{\"name\":\"unicode-ident\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"proc-macro\"],\"nightly\":[],\"proc-macro\":[],\"span-locations\":[]}}", - "prost-build_0.13.5": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"heck\",\"req\":\">=0.4, <=0.5\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\">=0.10, <=0.14\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"name\":\"multimap\",\"req\":\">=0.8, <=0.10\"},{\"name\":\"once_cell\",\"req\":\"^1.17.1\"},{\"default_features\":false,\"name\":\"petgraph\",\"req\":\">=0.6, <=0.7\"},{\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"prost\",\"req\":\"^0.13.5\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.13.5\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"pulldown-cmark-to-cmark\",\"optional\":true,\"req\":\">=16, <=20\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-bool\"],\"name\":\"regex\",\"req\":\"^1.8.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"cleanup-markdown\":[\"dep:pulldown-cmark\",\"dep:pulldown-cmark-to-cmark\"],\"default\":[\"format\"],\"format\":[\"dep:prettyplease\",\"dep:syn\"]}}", "prost-build_0.14.3": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"heck\",\"req\":\">=0.4, <=0.5\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\">=0.10, <=0.14\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"name\":\"multimap\",\"req\":\">=0.8, <=0.10\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"petgraph\",\"req\":\"^0.8\"},{\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"prost\",\"req\":\"^0.14.3\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.3\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13\"},{\"name\":\"pulldown-cmark-to-cmark\",\"optional\":true,\"req\":\"^22\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-bool\"],\"name\":\"regex\",\"req\":\"^1.8.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"cleanup-markdown\":[\"dep:pulldown-cmark\",\"dep:pulldown-cmark-to-cmark\"],\"default\":[\"format\"],\"format\":[\"dep:prettyplease\",\"dep:syn\"]}}", - "prost-derive_0.13.5": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.1\"},{\"name\":\"itertools\",\"req\":\">=0.10.1, <=0.14\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", + "prost-build_0.14.4": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"heck\",\"req\":\">=0.4, <=0.5\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\">=0.10, <=0.14\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"name\":\"multimap\",\"req\":\">=0.8, <=0.10\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"petgraph\",\"req\":\"^0.8\"},{\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"prost\",\"req\":\"^0.14.4\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.4\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13\"},{\"name\":\"pulldown-cmark-to-cmark\",\"optional\":true,\"req\":\"^22\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-bool\"],\"name\":\"regex\",\"req\":\"^1.8.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"default_features\":false,\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"cleanup-markdown\":[\"dep:pulldown-cmark\",\"dep:pulldown-cmark-to-cmark\"],\"default\":[\"format\"],\"format\":[\"dep:prettyplease\",\"dep:syn\"]}}", "prost-derive_0.14.3": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.1\"},{\"name\":\"itertools\",\"req\":\">=0.10.1, <=0.14\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", - "prost-types_0.13.5": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"prost-derive\"],\"name\":\"prost\",\"req\":\"^0.13.5\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\"],\"std\":[\"prost/std\"]}}", + "prost-derive_0.14.4": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.1\"},{\"name\":\"itertools\",\"req\":\">=0.10.1, <=0.14\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", "prost-types_0.14.3": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.4\"},{\"default_features\":false,\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.34\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"prost\",\"req\":\"^0.14.3\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\"],\"std\":[\"prost/std\"]}}", - "prost_0.13.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"name\":\"prost-derive\",\"optional\":true,\"req\":\"^0.13.5\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"}],\"features\":{\"default\":[\"derive\",\"std\"],\"derive\":[\"dep:prost-derive\"],\"no-recursion-limit\":[],\"prost-derive\":[\"derive\"],\"std\":[]}}", + "prost-types_0.14.4": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.4\"},{\"default_features\":false,\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.34\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"prost\",\"req\":\"^0.14.4\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\"],\"std\":[\"prost/std\"]}}", "prost_0.14.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"name\":\"prost-derive\",\"optional\":true,\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"}],\"features\":{\"default\":[\"derive\",\"std\"],\"derive\":[\"dep:prost-derive\"],\"no-recursion-limit\":[],\"std\":[]}}", + "prost_0.14.4": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"name\":\"prost-derive\",\"optional\":true,\"req\":\"^0.14.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"}],\"features\":{\"default\":[\"derive\",\"std\"],\"derive\":[\"dep:prost-derive\"],\"no-recursion-limit\":[],\"std\":[]}}", "protoc-gen-prost_0.5.0": "{\"dependencies\":[{\"name\":\"once_cell\",\"req\":\"^1.21.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"prost\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-build\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"regex\",\"req\":\"^1.11.1\"}],\"features\":{}}", "protoc-gen-tonic_0.5.0": "{\"dependencies\":[{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"prettyplease\",\"req\":\"^0.2.37\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.103\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"prost\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-build\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.1\"},{\"name\":\"protoc-gen-prost\",\"req\":\"^0.5.0\"},{\"name\":\"quote\",\"req\":\"^1.0.42\"},{\"default_features\":false,\"name\":\"regex\",\"req\":\"^1.11.1\"},{\"features\":[\"parsing\",\"full\"],\"name\":\"syn\",\"req\":\"^2.0.109\"},{\"name\":\"tonic-build\",\"req\":\"^0.14.1\"}],\"features\":{}}", "pyo3-build-config_0.28.3": "{\"dependencies\":[{\"name\":\"python3-dll-a\",\"optional\":true,\"req\":\"^0.2.12\"},{\"kind\":\"build\",\"name\":\"python3-dll-a\",\"optional\":true,\"req\":\"^0.2.12\"},{\"name\":\"target-lexicon\",\"req\":\"^0.13.3\"},{\"kind\":\"build\",\"name\":\"target-lexicon\",\"req\":\"^0.13.3\"}],\"features\":{\"abi3\":[],\"abi3-py310\":[\"abi3-py311\"],\"abi3-py311\":[\"abi3-py312\"],\"abi3-py312\":[\"abi3-py313\"],\"abi3-py313\":[\"abi3-py314\"],\"abi3-py314\":[\"abi3\"],\"abi3-py37\":[\"abi3-py38\"],\"abi3-py38\":[\"abi3-py39\"],\"abi3-py39\":[\"abi3-py310\"],\"default\":[],\"extension-module\":[],\"generate-import-lib\":[\"dep:python3-dll-a\"],\"resolve-config\":[]}}", @@ -1156,26 +1069,22 @@ "pyo3-macros-backend_0.28.3": "{\"dependencies\":[{\"name\":\"heck\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"features\":[\"resolve-config\"],\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"},{\"kind\":\"build\",\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0.37\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"full\",\"extra-traits\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.59\"}],\"features\":{\"experimental-async\":[],\"experimental-inspect\":[]}}", "pyo3-macros_0.28.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"pyo3-macros-backend\",\"req\":\"=0.28.3\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"experimental-async\":[\"pyo3-macros-backend/experimental-async\"],\"experimental-inspect\":[\"pyo3-macros-backend/experimental-inspect\"],\"multiple-pymethods\":[]}}", "pyo3_0.28.3": "{\"dependencies\":[{\"name\":\"anyhow\",\"optional\":true,\"req\":\"^1.0.1\"},{\"kind\":\"dev\",\"name\":\"assert_approx_eq\",\"req\":\"^1.1.0\"},{\"name\":\"bigdecimal\",\"optional\":true,\"req\":\"^0.4.7\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.10\"},{\"default_features\":false,\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.25\"},{\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.25\"},{\"default_features\":false,\"name\":\"chrono-tz\",\"optional\":true,\"req\":\">=0.10, <0.11\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\">=0.10, <0.11\"},{\"name\":\"either\",\"optional\":true,\"req\":\"^1.9\"},{\"name\":\"eyre\",\"optional\":true,\"req\":\">=0.6.8, <0.7\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.28\"},{\"default_features\":false,\"name\":\"hashbrown\",\"optional\":true,\"req\":\">=0.15.0, <0.17\"},{\"features\":[\"fallback\"],\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\">=2.5.0, <3\"},{\"name\":\"inventory\",\"optional\":true,\"req\":\"^0.3.5\"},{\"name\":\"jiff-02\",\"optional\":true,\"package\":\"jiff\",\"req\":\"^0.2\"},{\"name\":\"libc\",\"req\":\"^0.2.62\"},{\"name\":\"lock_api\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"num-bigint\",\"optional\":true,\"req\":\"^0.4.4\"},{\"name\":\"num-complex\",\"optional\":true,\"req\":\">=0.4.6, <0.5\"},{\"name\":\"num-rational\",\"optional\":true,\"req\":\"^0.4.1\"},{\"name\":\"num-traits\",\"optional\":true,\"req\":\"^0.2.16\"},{\"name\":\"once_cell\",\"req\":\"^1.21\"},{\"default_features\":false,\"name\":\"ordered-float\",\"optional\":true,\"req\":\"^5.0.0\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12\"},{\"features\":[\"arc_lock\"],\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"^0.12.3\"},{\"name\":\"portable-atomic\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_has_atomic = \\\"64\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0\"},{\"features\":[\"resolve-config\"],\"kind\":\"build\",\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"},{\"name\":\"pyo3-ffi\",\"req\":\"=0.28.3\"},{\"name\":\"pyo3-macros\",\"optional\":true,\"req\":\"=0.28.3\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.6.1\"},{\"default_features\":false,\"name\":\"rust_decimal\",\"optional\":true,\"req\":\"^1.15\"},{\"kind\":\"dev\",\"name\":\"send_wrapper\",\"req\":\"^0.6\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.61\"},{\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.12.0\"},{\"default_features\":false,\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.38\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\">=1.0.115\"},{\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.12.0\"},{\"features\":[\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.10.0\"}],\"features\":{\"abi3\":[\"pyo3-build-config/abi3\",\"pyo3-ffi/abi3\"],\"abi3-py310\":[\"abi3-py311\",\"pyo3-build-config/abi3-py310\",\"pyo3-ffi/abi3-py310\"],\"abi3-py311\":[\"abi3-py312\",\"pyo3-build-config/abi3-py311\",\"pyo3-ffi/abi3-py311\"],\"abi3-py312\":[\"abi3-py313\",\"pyo3-build-config/abi3-py312\",\"pyo3-ffi/abi3-py312\"],\"abi3-py313\":[\"abi3-py314\",\"pyo3-build-config/abi3-py313\",\"pyo3-ffi/abi3-py313\"],\"abi3-py314\":[\"abi3\",\"pyo3-build-config/abi3-py314\",\"pyo3-ffi/abi3-py314\"],\"abi3-py37\":[\"abi3-py38\",\"pyo3-build-config/abi3-py37\",\"pyo3-ffi/abi3-py37\"],\"abi3-py38\":[\"abi3-py39\",\"pyo3-build-config/abi3-py38\",\"pyo3-ffi/abi3-py38\"],\"abi3-py39\":[\"abi3-py310\",\"pyo3-build-config/abi3-py39\",\"pyo3-ffi/abi3-py39\"],\"arc_lock\":[\"lock_api\",\"lock_api/arc_lock\",\"parking_lot?/arc_lock\"],\"auto-initialize\":[],\"bigdecimal\":[\"dep:bigdecimal\",\"num-bigint\"],\"chrono-local\":[\"chrono/clock\",\"dep:iana-time-zone\"],\"default\":[\"macros\"],\"experimental-async\":[\"macros\",\"pyo3-macros/experimental-async\"],\"experimental-inspect\":[\"pyo3-macros/experimental-inspect\"],\"extension-module\":[\"pyo3-ffi/extension-module\"],\"full\":[\"macros\",\"anyhow\",\"arc_lock\",\"bigdecimal\",\"bytes\",\"chrono\",\"chrono-local\",\"chrono-tz\",\"either\",\"experimental-async\",\"experimental-inspect\",\"eyre\",\"hashbrown\",\"indexmap\",\"jiff-02\",\"lock_api\",\"num-bigint\",\"num-complex\",\"num-rational\",\"ordered-float\",\"parking_lot\",\"py-clone\",\"rust_decimal\",\"serde\",\"smallvec\",\"time\",\"uuid\"],\"generate-import-lib\":[\"pyo3-ffi/generate-import-lib\"],\"macros\":[\"pyo3-macros\"],\"multiple-pymethods\":[\"inventory\",\"pyo3-macros/multiple-pymethods\"],\"nightly\":[],\"num-bigint\":[\"dep:num-bigint\",\"dep:num-traits\"],\"parking_lot\":[\"dep:parking_lot\",\"lock_api\"],\"py-clone\":[]}}", - "quick-xml_0.31.0": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"memchr\",\"req\":\"^2.1\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\">=1.0.100\"},{\"kind\":\"dev\",\"name\":\"serde-value\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.79\"},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.10\"},{\"default_features\":false,\"features\":[\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.21\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4\"}],\"features\":{\"async-tokio\":[\"tokio\"],\"default\":[],\"encoding\":[\"encoding_rs\"],\"escape-html\":[],\"overlapped-lists\":[],\"serde-types\":[\"serde/derive\"],\"serialize\":[\"serde\"]}}", - "quinn-proto_0.11.14": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0.1\"},{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.1\"},{\"default_features\":false,\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.9\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"fastbloom\",\"optional\":true,\"req\":\"^0.14\"},{\"default_features\":false,\"features\":[\"wasm_js\"],\"name\":\"getrandom\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"name\":\"lru-slab\",\"req\":\"^0.1.2\"},{\"name\":\"qlog\",\"optional\":true,\"req\":\"^0.15.2\"},{\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14\"},{\"features\":[\"wasm32_unknown_unknown_js\"],\"name\":\"ring\",\"req\":\"^0.17\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"name\":\"rustc-hash\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.5\"},{\"features\":[\"web\"],\"name\":\"rustls-pki-types\",\"req\":\"^1.7\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"rustls-platform-verifier\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"slab\",\"req\":\"^0.4.6\"},{\"name\":\"thiserror\",\"req\":\"^2.0.3\"},{\"features\":[\"alloc\",\"alloc\"],\"name\":\"tinyvec\",\"req\":\"^1.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.10\"},{\"default_features\":false,\"features\":[\"env-filter\",\"fmt\",\"ansi\",\"time\",\"local-time\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.45\"},{\"name\":\"web-time\",\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"}],\"features\":{\"__rustls-post-quantum-test\":[],\"aws-lc-rs\":[\"dep:aws-lc-rs\",\"aws-lc-rs?/aws-lc-sys\",\"aws-lc-rs?/prebuilt-nasm\"],\"aws-lc-rs-fips\":[\"aws-lc-rs\",\"aws-lc-rs?/fips\"],\"bloom\":[\"dep:fastbloom\"],\"default\":[\"rustls-ring\",\"log\",\"bloom\"],\"log\":[\"tracing/log\"],\"platform-verifier\":[\"dep:rustls-platform-verifier\"],\"qlog\":[\"dep:qlog\"],\"ring\":[\"dep:ring\"],\"rustls\":[\"rustls-ring\"],\"rustls-aws-lc-rs\":[\"dep:rustls\",\"rustls?/aws-lc-rs\",\"aws-lc-rs\"],\"rustls-aws-lc-rs-fips\":[\"rustls-aws-lc-rs\",\"aws-lc-rs-fips\"],\"rustls-log\":[\"rustls?/logging\"],\"rustls-ring\":[\"dep:rustls\",\"rustls?/ring\",\"ring\"]}}", - "quinn-udp_0.5.14": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cfg_aliases\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"async_tokio\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"name\":\"libc\",\"req\":\"^0.2.158\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"req\":\"^1.19\",\"target\":\"cfg(windows)\"},{\"name\":\"socket2\",\"req\":\">=0.5, <0.7\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"features\":[\"sync\",\"rt\",\"rt-multi-thread\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.28.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.10\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_IO\",\"Win32_Networking_WinSock\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <=0.60\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"tracing\",\"log\"],\"direct-log\":[\"dep:log\"],\"fast-apple-datapath\":[],\"log\":[\"tracing/log\"]}}", - "quinn_0.11.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.22\"},{\"name\":\"async-io\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"async-std\",\"optional\":true,\"req\":\"^1.11\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"build\",\"name\":\"cfg_aliases\",\"req\":\"^0.2\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4\"},{\"kind\":\"dev\",\"name\":\"crc\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"directories-next\",\"req\":\"^2\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.19\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"proto\",\"package\":\"quinn-proto\",\"req\":\"^0.11.12\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14\"},{\"name\":\"rustc-hash\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.5\"},{\"kind\":\"dev\",\"name\":\"rustls-pemfile\",\"req\":\"^2\"},{\"name\":\"smol\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"socket2\",\"req\":\">=0.5, <0.7\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"thiserror\",\"req\":\"^2.0.3\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"req\":\"^1.28.1\"},{\"features\":[\"sync\",\"rt\",\"rt-multi-thread\",\"time\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.28.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.10\"},{\"default_features\":false,\"features\":[\"std-future\"],\"kind\":\"dev\",\"name\":\"tracing-futures\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"env-filter\",\"fmt\",\"ansi\",\"time\",\"local-time\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"default_features\":false,\"features\":[\"tracing\"],\"name\":\"udp\",\"package\":\"quinn-udp\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"url\",\"req\":\"^2\"},{\"name\":\"web-time\",\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"}],\"features\":{\"aws-lc-rs\":[\"proto/aws-lc-rs\"],\"aws-lc-rs-fips\":[\"proto/aws-lc-rs-fips\"],\"bloom\":[\"proto/bloom\"],\"default\":[\"log\",\"platform-verifier\",\"runtime-tokio\",\"rustls-ring\",\"bloom\"],\"lock_tracking\":[],\"log\":[\"tracing/log\",\"proto/log\",\"udp/log\"],\"platform-verifier\":[\"proto/platform-verifier\"],\"qlog\":[\"proto/qlog\"],\"ring\":[\"proto/ring\"],\"runtime-async-std\":[\"async-io\",\"async-std\"],\"runtime-smol\":[\"async-io\",\"smol\"],\"runtime-tokio\":[\"tokio/time\",\"tokio/rt\",\"tokio/net\"],\"rustls\":[\"rustls-ring\"],\"rustls-aws-lc-rs\":[\"dep:rustls\",\"aws-lc-rs\",\"proto/rustls-aws-lc-rs\",\"proto/aws-lc-rs\"],\"rustls-aws-lc-rs-fips\":[\"dep:rustls\",\"aws-lc-rs-fips\",\"proto/rustls-aws-lc-rs-fips\",\"proto/aws-lc-rs-fips\"],\"rustls-log\":[\"rustls?/logging\"],\"rustls-ring\":[\"dep:rustls\",\"ring\",\"proto/rustls-ring\",\"proto/ring\"]}}", + "quick-error_1.2.3": "{\"dependencies\":[],\"features\":{}}", + "quick-xml_0.41.0": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\">=0.4, <0.9\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"memchr\",\"req\":\"^2.1\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\">=1.0.180\"},{\"kind\":\"dev\",\"name\":\"serde-value\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.206\"},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.10\"},{\"default_features\":false,\"features\":[\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.21\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4\"}],\"features\":{\"async-tokio\":[\"tokio\"],\"default\":[],\"encoding\":[\"encoding_rs\"],\"escape-html\":[],\"overlapped-lists\":[],\"serde-types\":[\"serde/derive\"],\"serialize\":[\"serde\"]}}", "quote_1.0.45": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"default\":[\"proc-macro\"],\"proc-macro\":[\"proc-macro2/proc-macro\"]}}", "r-efi_5.3.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"efiapi\":[],\"examples\":[\"native\"],\"native\":[],\"rustc-dep-of-std\":[\"core\"]}}", "r-efi_6.0.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"native\":[],\"rustc-dep-of-std\":[\"core\"]}}", "radium_0.7.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"}],\"features\":{}}", "rand_0.10.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"rng\"],\"name\":\"chacha20\",\"optional\":true,\"req\":\"^0.10.0\"},{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.1.3\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.7\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.140\"}],\"features\":{\"alloc\":[],\"chacha\":[\"dep:chacha20\"],\"default\":[\"std\",\"std_rng\",\"sys_rng\",\"thread_rng\"],\"log\":[],\"serde\":[\"dep:serde\"],\"simd_support\":[],\"std\":[\"alloc\",\"getrandom?/std\"],\"std_rng\":[\"dep:chacha20\"],\"sys_rng\":[\"dep:getrandom\",\"getrandom/sys_rng\"],\"thread_rng\":[\"std\",\"std_rng\",\"sys_rng\"],\"unbiased\":[]}}", - "rand_0.7.3": "{\"dependencies\":[{\"name\":\"getrandom_package\",\"optional\":true,\"package\":\"getrandom\",\"req\":\"^0.1.1\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.22\",\"target\":\"cfg(unix)\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.4\"},{\"features\":[\"into_bits\"],\"name\":\"packed_simd\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"rand_chacha\",\"req\":\"^0.2.1\",\"target\":\"cfg(not(target_os = \\\"emscripten\\\"))\"},{\"name\":\"rand_core\",\"req\":\"^0.5.1\"},{\"name\":\"rand_hc\",\"req\":\"^0.2\",\"target\":\"cfg(target_os = \\\"emscripten\\\")\"},{\"kind\":\"dev\",\"name\":\"rand_hc\",\"req\":\"^0.2\"},{\"name\":\"rand_pcg\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.2\"}],\"features\":{\"alloc\":[\"rand_core/alloc\"],\"default\":[\"std\"],\"getrandom\":[\"getrandom_package\",\"rand_core/getrandom\"],\"nightly\":[\"simd_support\"],\"serde1\":[],\"simd_support\":[\"packed_simd\"],\"small_rng\":[\"rand_pcg\"],\"std\":[\"rand_core/std\",\"rand_chacha/std\",\"alloc\",\"getrandom\",\"libc\"],\"stdweb\":[\"getrandom_package/stdweb\"],\"wasm-bindgen\":[\"getrandom_package/wasm-bindgen\"]}}", "rand_0.8.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.2.1\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.22\",\"target\":\"cfg(unix)\"},{\"default_features\":false,\"name\":\"rand_chacha\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"rand_core\",\"req\":\"^0.6.0\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.3.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.103\"}],\"features\":{\"alloc\":[\"rand_core/alloc\"],\"default\":[\"std\",\"std_rng\"],\"getrandom\":[\"rand_core/getrandom\"],\"log\":[],\"min_const_gen\":[],\"nightly\":[],\"serde1\":[\"serde\",\"rand_core/serde1\"],\"small_rng\":[],\"std\":[\"rand_core/std\",\"rand_chacha/std\",\"alloc\",\"getrandom\",\"libc\"],\"std_rng\":[\"rand_chacha\"]}}", "rand_0.9.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.2.1\"},{\"default_features\":false,\"name\":\"rand_chacha\",\"optional\":true,\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.7\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.140\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"std_rng\",\"os_rng\",\"small_rng\",\"thread_rng\"],\"log\":[],\"nightly\":[],\"os_rng\":[\"rand_core/os_rng\"],\"serde\":[\"dep:serde\",\"rand_core/serde\"],\"simd_support\":[],\"small_rng\":[],\"std\":[\"rand_core/std\",\"rand_chacha?/std\",\"alloc\"],\"std_rng\":[\"dep:rand_chacha\"],\"thread_rng\":[\"std\",\"std_rng\",\"os_rng\"],\"unbiased\":[]}}", - "rand_chacha_0.2.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"simd\"],\"name\":\"ppv-lite86\",\"req\":\"^0.2.6\"},{\"name\":\"rand_core\",\"req\":\"^0.5\"}],\"features\":{\"default\":[\"std\",\"simd\"],\"simd\":[],\"std\":[\"ppv-lite86/std\"]}}", "rand_chacha_0.3.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"simd\"],\"name\":\"ppv-lite86\",\"req\":\"^0.2.8\"},{\"name\":\"rand_core\",\"req\":\"^0.6.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"serde1\":[\"serde\"],\"simd\":[],\"std\":[\"ppv-lite86/std\"]}}", "rand_chacha_0.9.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"simd\"],\"name\":\"ppv-lite86\",\"req\":\"^0.2.14\"},{\"name\":\"rand_core\",\"req\":\"^0.9.0\"},{\"features\":[\"os_rng\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.9.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"os_rng\":[\"rand_core/os_rng\"],\"serde\":[\"dep:serde\"],\"std\":[\"ppv-lite86/std\",\"rand_core/std\"]}}", "rand_core_0.10.1": "{\"dependencies\":[],\"features\":{}}", - "rand_core_0.5.1": "{\"dependencies\":[{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.1\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[],\"serde1\":[\"serde\"],\"std\":[\"alloc\",\"getrandom\",\"getrandom/std\"]}}", "rand_core_0.6.4": "{\"dependencies\":[{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[],\"serde1\":[\"serde\"],\"std\":[\"alloc\",\"getrandom\",\"getrandom/std\"]}}", "rand_core_0.9.3": "{\"dependencies\":[{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"os_rng\":[\"dep:getrandom\"],\"serde\":[\"dep:serde\"],\"std\":[\"getrandom?/std\"]}}", - "rand_hc_0.2.0": "{\"dependencies\":[{\"name\":\"rand_core\",\"req\":\"^0.5\"}],\"features\":{}}", + "rayon-core_1.13.0": "{\"dependencies\":[{\"name\":\"crossbeam-deque\",\"req\":\"^0.8.1\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"scoped-tls\",\"req\":\"^1.0\"},{\"name\":\"wasm_sync\",\"optional\":true,\"req\":\"^0.1.0\"}],\"features\":{\"web_spin_lock\":[\"dep:wasm_sync\"]}}", + "rayon_1.12.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"either\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.4\"},{\"name\":\"rayon-core\",\"req\":\"^1.13.0\"},{\"name\":\"wasm_sync\",\"optional\":true,\"req\":\"^0.1.0\"}],\"features\":{\"web_spin_lock\":[\"dep:wasm_sync\",\"rayon-core/web_spin_lock\"]}}", "redis-protocol_6.0.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.1\"},{\"default_features\":false,\"name\":\"bytes-utils\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"cookie-factory\",\"req\":\"=0.3.2\"},{\"name\":\"crc16\",\"req\":\"^0.4\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.14\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.12\"},{\"name\":\"libm\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"nom\",\"req\":\"^7.1\"},{\"kind\":\"dev\",\"name\":\"pretty_env_logger\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.36\"},{\"features\":[\"codec\"],\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7\"}],\"features\":{\"alloc\":[\"nom/alloc\"],\"bytes\":[\"dep:bytes\",\"bytes-utils\"],\"codec\":[\"tokio-util\",\"bytes\"],\"convert\":[],\"decode-logs\":[],\"default\":[\"std\",\"resp2\",\"resp3\"],\"index-map\":[\"indexmap\"],\"resp2\":[],\"resp3\":[],\"std\":[\"cookie-factory/default\",\"nom/default\"]}}", "redis-test_1.0.0": "{\"dependencies\":[{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"redis\",\"req\":\"^1\"},{\"features\":[\"aio\",\"tokio-comp\"],\"kind\":\"dev\",\"name\":\"redis\",\"req\":\"^1\"},{\"name\":\"socket2\",\"req\":\"^0.6\"},{\"name\":\"tempfile\",\"req\":\"^3.23.0\"},{\"features\":[\"rt\",\"macros\",\"rt-multi-thread\",\"test-util\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"}],\"features\":{\"aio\":[\"futures\",\"redis/aio\"]}}", "redis_1.0.0": "{\"dependencies\":[{\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.8.11\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"name\":\"arc-swap\",\"optional\":true,\"req\":\"^1.7.1\"},{\"name\":\"arcstr\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"assert_approx_eq\",\"req\":\"^1.0\"},{\"name\":\"async-io\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"async-native-tls\",\"optional\":true,\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"backon\",\"optional\":true,\"req\":\"^1.6.0\"},{\"name\":\"bb8\",\"optional\":true,\"req\":\"^0.9.1\"},{\"name\":\"bigdecimal\",\"optional\":true,\"req\":\"^0.4.9\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"cfg-if\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"combine\",\"req\":\"^4.6\"},{\"name\":\"crc16\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"futures-rustls\",\"optional\":true,\"req\":\"^0.26\"},{\"kind\":\"dev\",\"name\":\"futures-time\",\"req\":\"^3\"},{\"default_features\":false,\"features\":[\"std\",\"sink\"],\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.31\"},{\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.16\"},{\"name\":\"itoa\",\"req\":\"^1.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"lru\",\"optional\":true,\"req\":\"^0.16\"},{\"name\":\"native-tls\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"num-bigint\",\"optional\":true,\"req\":\"^0.4.6\"},{\"features\":[\"tokio\",\"quickcheck1\"],\"kind\":\"dev\",\"name\":\"partial-io\",\"req\":\"^0.5\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"name\":\"r2d2\",\"optional\":true,\"req\":\"^0.8.10\"},{\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"name\":\"rust_decimal\",\"optional\":true,\"req\":\"^1.39.0\"},{\"default_features\":false,\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23\"},{\"features\":[\"ring\"],\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"ryu\",\"req\":\"^1.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.219\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.145\"},{\"name\":\"sha1_smol\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"smol\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"smol-timeout\",\"optional\":true,\"req\":\"^0.6\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"req\":\"^0.6\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.23.0\"},{\"features\":[\"rt\",\"net\",\"time\",\"sync\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"rt\",\"macros\",\"rt-multi-thread\",\"test-util\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-native-tls\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26\"},{\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"url\",\"req\":\"^2.5\"},{\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.18.1\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"xxh3\"],\"name\":\"xxhash-rust\",\"req\":\"^0.8\"}],\"features\":{\"acl\":[],\"aio\":[\"bytes\",\"dep:pin-project-lite\",\"dep:futures-util\",\"dep:tokio\",\"dep:tokio-util\",\"tokio-util/codec\",\"combine/tokio\",\"dep:cfg-if\"],\"bb8\":[\"dep:bb8\"],\"cache-aio\":[\"aio\",\"dep:lru\"],\"cluster\":[\"dep:crc16\",\"dep:rand\"],\"cluster-async\":[\"aio\",\"cluster\",\"dep:log\"],\"connection-manager\":[\"dep:arc-swap\",\"dep:futures-channel\",\"aio\",\"dep:backon\"],\"default\":[\"acl\",\"streams\",\"geospatial\",\"script\",\"num-bigint\"],\"geospatial\":[],\"json\":[\"dep:serde\",\"serde/derive\",\"dep:serde_json\"],\"num-bigint\":[\"dep:num-bigint\"],\"r2d2\":[\"dep:r2d2\"],\"script\":[\"dep:sha1_smol\"],\"sentinel\":[\"dep:rand\"],\"smol-comp\":[\"aio\",\"dep:smol\",\"dep:smol-timeout\",\"dep:async-io\"],\"smol-native-tls-comp\":[\"smol-comp\",\"dep:async-native-tls\",\"tls-native-tls\"],\"smol-rustls-comp\":[\"smol-comp\",\"dep:futures-rustls\",\"tls-rustls\"],\"streams\":[],\"tls-native-tls\":[\"dep:native-tls\"],\"tls-rustls\":[\"dep:rustls\",\"rustls/std\",\"dep:rustls-native-certs\"],\"tls-rustls-insecure\":[\"tls-rustls\"],\"tls-rustls-webpki-roots\":[\"tls-rustls\",\"dep:webpki-roots\"],\"tokio-comp\":[\"aio\",\"tokio/net\"],\"tokio-native-tls-comp\":[\"tokio-comp\",\"tls-native-tls\",\"dep:tokio-native-tls\"],\"tokio-rustls-comp\":[\"tokio-comp\",\"tls-rustls\",\"dep:tokio-rustls\"],\"vector-sets\":[\"dep:serde\",\"serde/derive\",\"dep:serde_json\"]}}", @@ -1189,31 +1098,33 @@ "regex_1.12.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aho-corasick\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.69\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"atty\",\"humantime\",\"termcolor\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.9.3\"},{\"default_features\":false,\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.6.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"features\":[\"alloc\",\"syntax\",\"meta\",\"nfa-pikevm\"],\"name\":\"regex-automata\",\"req\":\"^0.4.12\"},{\"default_features\":false,\"name\":\"regex-syntax\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex-test\",\"req\":\"^0.1.0\"}],\"features\":{\"default\":[\"std\",\"perf\",\"unicode\",\"regex-syntax/default\"],\"logging\":[\"aho-corasick?/logging\",\"memchr?/logging\",\"regex-automata/logging\"],\"pattern\":[],\"perf\":[\"perf-cache\",\"perf-dfa\",\"perf-onepass\",\"perf-backtrack\",\"perf-inline\",\"perf-literal\"],\"perf-backtrack\":[\"regex-automata/nfa-backtrack\"],\"perf-cache\":[],\"perf-dfa\":[\"regex-automata/hybrid\"],\"perf-dfa-full\":[\"regex-automata/dfa-build\",\"regex-automata/dfa-search\"],\"perf-inline\":[\"regex-automata/perf-inline\"],\"perf-literal\":[\"dep:aho-corasick\",\"dep:memchr\",\"regex-automata/perf-literal\"],\"perf-onepass\":[\"regex-automata/dfa-onepass\"],\"std\":[\"aho-corasick?/std\",\"memchr?/std\",\"regex-automata/std\",\"regex-syntax/std\"],\"unicode\":[\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"regex-automata/unicode\",\"regex-syntax/unicode\"],\"unicode-age\":[\"regex-automata/unicode-age\",\"regex-syntax/unicode-age\"],\"unicode-bool\":[\"regex-automata/unicode-bool\",\"regex-syntax/unicode-bool\"],\"unicode-case\":[\"regex-automata/unicode-case\",\"regex-syntax/unicode-case\"],\"unicode-gencat\":[\"regex-automata/unicode-gencat\",\"regex-syntax/unicode-gencat\"],\"unicode-perl\":[\"regex-automata/unicode-perl\",\"regex-automata/unicode-word-boundary\",\"regex-syntax/unicode-perl\"],\"unicode-script\":[\"regex-automata/unicode-script\",\"regex-syntax/unicode-script\"],\"unicode-segment\":[\"regex-automata/unicode-segment\",\"regex-syntax/unicode-segment\"],\"unstable\":[\"pattern\"],\"use_std\":[\"std\"]}}", "regex_1.12.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aho-corasick\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.69\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"atty\",\"humantime\",\"termcolor\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.9.3\"},{\"default_features\":false,\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.6.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"features\":[\"alloc\",\"syntax\",\"meta\",\"nfa-pikevm\"],\"name\":\"regex-automata\",\"req\":\"^0.4.12\"},{\"default_features\":false,\"name\":\"regex-syntax\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex-test\",\"req\":\"^0.1.0\"}],\"features\":{\"default\":[\"std\",\"perf\",\"unicode\",\"regex-syntax/default\"],\"logging\":[\"aho-corasick?/logging\",\"memchr?/logging\",\"regex-automata/logging\"],\"pattern\":[],\"perf\":[\"perf-cache\",\"perf-dfa\",\"perf-onepass\",\"perf-backtrack\",\"perf-inline\",\"perf-literal\"],\"perf-backtrack\":[\"regex-automata/nfa-backtrack\"],\"perf-cache\":[],\"perf-dfa\":[\"regex-automata/hybrid\"],\"perf-dfa-full\":[\"regex-automata/dfa-build\",\"regex-automata/dfa-search\"],\"perf-inline\":[\"regex-automata/perf-inline\"],\"perf-literal\":[\"dep:aho-corasick\",\"dep:memchr\",\"regex-automata/perf-literal\"],\"perf-onepass\":[\"regex-automata/dfa-onepass\"],\"std\":[\"aho-corasick?/std\",\"memchr?/std\",\"regex-automata/std\",\"regex-syntax/std\"],\"unicode\":[\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"regex-automata/unicode\",\"regex-syntax/unicode\"],\"unicode-age\":[\"regex-automata/unicode-age\",\"regex-syntax/unicode-age\"],\"unicode-bool\":[\"regex-automata/unicode-bool\",\"regex-syntax/unicode-bool\"],\"unicode-case\":[\"regex-automata/unicode-case\",\"regex-syntax/unicode-case\"],\"unicode-gencat\":[\"regex-automata/unicode-gencat\",\"regex-syntax/unicode-gencat\"],\"unicode-perl\":[\"regex-automata/unicode-perl\",\"regex-automata/unicode-word-boundary\",\"regex-syntax/unicode-perl\"],\"unicode-script\":[\"regex-automata/unicode-script\",\"regex-syntax/unicode-script\"],\"unicode-segment\":[\"regex-automata/unicode-segment\",\"regex-syntax/unicode-segment\"],\"unstable\":[\"pattern\"],\"use_std\":[\"std\"]}}", "relative-path_2.0.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.76\"},{\"kind\":\"dev\",\"name\":\"foldhash\",\"req\":\"^0.1.5\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.160\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.160\"}],\"features\":{\"alloc\":[\"serde?/alloc\"],\"default\":[\"std\",\"alloc\"],\"serde\":[\"dep:serde\"],\"std\":[]}}", - "reqwest-middleware_0.4.2": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.51\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"reqwest\",\"req\":\"^0.12.0\"},{\"features\":[\"rustls-tls\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12.0\"},{\"name\":\"serde\",\"req\":\"^1.0.106\"},{\"name\":\"thiserror\",\"req\":\"^1.0.21\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0.0\"},{\"name\":\"tower-service\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"wiremock\",\"req\":\"^0.6.0\"}],\"features\":{\"charset\":[\"reqwest/charset\"],\"http2\":[\"reqwest/http2\"],\"json\":[\"reqwest/json\"],\"multipart\":[\"reqwest/multipart\"],\"rustls-tls\":[\"reqwest/rustls-tls\"]}}", - "reqwest_0.12.24": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"tokio\"],\"name\":\"async-compression\",\"optional\":true,\"req\":\"^0.4.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"brotli_crate\",\"package\":\"brotli\",\"req\":\"^8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"bytes\",\"req\":\"^1.2\"},{\"name\":\"cookie_crate\",\"optional\":true,\"package\":\"cookie\",\"req\":\"^0.18.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"cookie_store\",\"optional\":true,\"req\":\"^0.21.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0.13\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.28\"},{\"default_features\":false,\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.28\"},{\"default_features\":false,\"features\":[\"std\",\"alloc\"],\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.28\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"h3\",\"optional\":true,\"req\":\"^0.0.8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"h3-quinn\",\"optional\":true,\"req\":\"^0.0.10\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"tokio\"],\"name\":\"hickory-resolver\",\"optional\":true,\"req\":\"^0.25\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"http\",\"req\":\"^1.1\"},{\"name\":\"http-body\",\"req\":\"^1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"http-body-util\",\"req\":\"^0.1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"http1\",\"client\"],\"name\":\"hyper\",\"req\":\"^1.1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"http1\",\"http2\",\"client\",\"server\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"http1\",\"tls12\"],\"name\":\"hyper-rustls\",\"optional\":true,\"req\":\"^0.27.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"hyper-tls\",\"optional\":true,\"req\":\"^0.6\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"http1\",\"client\",\"client-legacy\",\"client-proxy\",\"tokio\"],\"name\":\"hyper-util\",\"req\":\"^0.1.12\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"http1\",\"http2\",\"client\",\"client-legacy\",\"server-auto\",\"server-graceful\",\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1.12\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"js-sys\",\"req\":\"^0.3.77\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0\"},{\"name\":\"log\",\"req\":\"^0.4.17\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"mime\",\"optional\":true,\"req\":\"^0.3.16\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2.0\"},{\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\",\"req\":\"^0.2.10\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.0\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.18\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"rustls\",\"runtime-tokio\"],\"name\":\"quinn\",\"optional\":true,\"req\":\"^0.11.1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.4\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"std\"],\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1.9.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"serde_json\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_urlencoded\",\"req\":\"^0.7.1\"},{\"features\":[\"futures\"],\"name\":\"sync_wrapper\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"net\",\"time\"],\"name\":\"tokio\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"tokio-native-tls\",\"optional\":true,\"req\":\"^0.3.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7.9\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"retry\",\"timeout\",\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"limit\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"default_features\":false,\"features\":[\"follow-redirect\"],\"name\":\"tower-http\",\"req\":\"^0.6.5\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"tower-service\",\"req\":\"^0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"url\",\"req\":\"^2.4\"},{\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"features\":[\"serde-serialize\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"wasm-bindgen-futures\",\"req\":\"^0.4.18\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"wasm-streams\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"features\":[\"AbortController\",\"AbortSignal\",\"Headers\",\"Request\",\"RequestInit\",\"RequestMode\",\"Response\",\"Window\",\"FormData\",\"Blob\",\"BlobPropertyBag\",\"ServiceWorkerGlobalScope\",\"RequestCredentials\",\"File\",\"ReadableStream\",\"RequestCache\"],\"name\":\"web-sys\",\"req\":\"^0.3.28\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"zstd_crate\",\"package\":\"zstd\",\"req\":\"^0.13\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"}],\"features\":{\"__rustls\":[\"dep:hyper-rustls\",\"dep:tokio-rustls\",\"dep:rustls\",\"__tls\"],\"__rustls-ring\":[\"hyper-rustls?/ring\",\"tokio-rustls?/ring\",\"rustls?/ring\",\"quinn?/ring\"],\"__tls\":[\"dep:rustls-pki-types\",\"tokio/io-util\"],\"blocking\":[\"dep:futures-channel\",\"futures-channel?/sink\",\"dep:futures-util\",\"futures-util?/io\",\"futures-util?/sink\",\"tokio/sync\"],\"brotli\":[\"dep:async-compression\",\"async-compression?/brotli\",\"dep:futures-util\",\"dep:tokio-util\"],\"charset\":[\"dep:encoding_rs\",\"dep:mime\"],\"cookies\":[\"dep:cookie_crate\",\"dep:cookie_store\"],\"default\":[\"default-tls\",\"charset\",\"http2\",\"system-proxy\"],\"default-tls\":[\"dep:hyper-tls\",\"dep:native-tls-crate\",\"__tls\",\"dep:tokio-native-tls\"],\"deflate\":[\"dep:async-compression\",\"async-compression?/zlib\",\"dep:futures-util\",\"dep:tokio-util\"],\"gzip\":[\"dep:async-compression\",\"async-compression?/gzip\",\"dep:futures-util\",\"dep:tokio-util\"],\"hickory-dns\":[\"dep:hickory-resolver\",\"dep:once_cell\"],\"http2\":[\"h2\",\"hyper/http2\",\"hyper-util/http2\",\"hyper-rustls?/http2\"],\"http3\":[\"rustls-tls-manual-roots\",\"dep:h3\",\"dep:h3-quinn\",\"dep:quinn\",\"tokio/macros\"],\"json\":[\"dep:serde_json\"],\"macos-system-configuration\":[\"system-proxy\"],\"multipart\":[\"dep:mime_guess\",\"dep:futures-util\"],\"native-tls\":[\"default-tls\"],\"native-tls-alpn\":[\"native-tls\",\"native-tls-crate?/alpn\",\"hyper-tls?/alpn\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate?/vendored\"],\"rustls-tls\":[\"rustls-tls-webpki-roots\"],\"rustls-tls-manual-roots\":[\"rustls-tls-manual-roots-no-provider\",\"__rustls-ring\"],\"rustls-tls-manual-roots-no-provider\":[\"__rustls\"],\"rustls-tls-native-roots\":[\"rustls-tls-native-roots-no-provider\",\"__rustls-ring\"],\"rustls-tls-native-roots-no-provider\":[\"dep:rustls-native-certs\",\"hyper-rustls?/native-tokio\",\"__rustls\"],\"rustls-tls-no-provider\":[\"rustls-tls-manual-roots-no-provider\"],\"rustls-tls-webpki-roots\":[\"rustls-tls-webpki-roots-no-provider\",\"__rustls-ring\"],\"rustls-tls-webpki-roots-no-provider\":[\"dep:webpki-roots\",\"hyper-rustls?/webpki-tokio\",\"__rustls\"],\"socks\":[],\"stream\":[\"tokio/fs\",\"dep:futures-util\",\"dep:tokio-util\",\"dep:wasm-streams\"],\"system-proxy\":[\"hyper-util/client-proxy-system\"],\"trust-dns\":[],\"zstd\":[\"dep:async-compression\",\"async-compression?/zstd\",\"dep:futures-util\",\"dep:tokio-util\"]}}", + "reqwest-middleware_0.5.2": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.51\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"reqwest\",\"req\":\"^0.13.1\"},{\"features\":[\"rustls\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.13.1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.106\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0.0\"},{\"name\":\"tower-service\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"wiremock\",\"req\":\"^0.6.0\"}],\"features\":{\"charset\":[\"reqwest/charset\"],\"form\":[\"reqwest/form\",\"dep:serde\"],\"http2\":[\"reqwest/http2\"],\"json\":[\"reqwest/json\",\"dep:serde\"],\"multipart\":[\"reqwest/multipart\"],\"query\":[\"reqwest/query\",\"dep:serde\"],\"rustls\":[\"reqwest/rustls\"],\"stream\":[\"reqwest/stream\"]}}", "reqwest_0.13.4": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"brotli_crate\",\"package\":\"brotli\",\"req\":\"^8\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"bytes\",\"req\":\"^1.2\"},{\"name\":\"cookie_crate\",\"optional\":true,\"package\":\"cookie\",\"req\":\"^0.18.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"cookie_store\",\"optional\":true,\"req\":\"^0.22.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0.13\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.28\"},{\"default_features\":false,\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.28\"},{\"default_features\":false,\"features\":[\"std\",\"alloc\"],\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.28\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"h3\",\"optional\":true,\"req\":\"^0.0.8\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"h3-quinn\",\"optional\":true,\"req\":\"^0.0.10\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"features\":[\"tokio\"],\"name\":\"hickory-resolver\",\"optional\":true,\"req\":\"^0.26\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"http\",\"req\":\"^1.1\"},{\"name\":\"http-body\",\"req\":\"^1\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.2\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"features\":[\"http1\",\"client\"],\"name\":\"hyper\",\"req\":\"^1.1\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"http1\",\"http2\",\"client\",\"server\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"http1\",\"tls12\"],\"name\":\"hyper-rustls\",\"optional\":true,\"req\":\"^0.27.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"hyper-tls\",\"optional\":true,\"req\":\"^0.6\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"features\":[\"http1\",\"client\",\"client-legacy\",\"client-proxy\",\"tokio\"],\"name\":\"hyper-util\",\"req\":\"^0.1.12\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"features\":[\"http1\",\"http2\",\"client\",\"client-legacy\",\"server-auto\",\"server-graceful\",\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1.12\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"js-sys\",\"req\":\"^0.3.77\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0\"},{\"name\":\"log\",\"req\":\"^0.4.17\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"mime\",\"optional\":true,\"req\":\"^0.3.16\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2.0\"},{\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\",\"req\":\"^0.2.16\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.0\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.18\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"runtime-tokio\"],\"name\":\"quinn\",\"optional\":true,\"req\":\"^0.11.1\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.4\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"features\":[\"std\"],\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1.9.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"rustls-platform-verifier\",\"optional\":true,\"req\":\">=0.6.0, <0.8.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_urlencoded\",\"optional\":true,\"req\":\"^0.7.1\"},{\"features\":[\"futures\"],\"name\":\"sync_wrapper\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"net\",\"time\"],\"name\":\"tokio\",\"req\":\"^1.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"tokio-native-tls\",\"optional\":true,\"req\":\"^0.3.0\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"io\"],\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7.9\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"retry\",\"timeout\",\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"default_features\":false,\"features\":[\"limit\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"default_features\":false,\"features\":[\"follow-redirect\"],\"name\":\"tower-http\",\"req\":\"^0.6.8\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"tower-service\",\"req\":\"^0.3\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"},{\"name\":\"url\",\"req\":\"^2.4\"},{\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"features\":[\"serde-serialize\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"name\":\"wasm-bindgen-futures\",\"req\":\"^0.4.18\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"name\":\"wasm-streams\",\"optional\":true,\"req\":\"^0.5\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"features\":[\"AbortController\",\"AbortSignal\",\"Headers\",\"Request\",\"RequestInit\",\"RequestMode\",\"Response\",\"Window\",\"FormData\",\"Blob\",\"BlobPropertyBag\",\"ServiceWorkerGlobalScope\",\"RequestCredentials\",\"File\",\"ReadableStream\",\"RequestCache\"],\"name\":\"web-sys\",\"req\":\"^0.3.28\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"zstd_crate\",\"package\":\"zstd\",\"req\":\"^0.13\",\"target\":\"cfg(not(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"))))\"}],\"features\":{\"__native-tls\":[\"dep:hyper-tls\",\"dep:native-tls-crate\",\"__tls\",\"dep:tokio-native-tls\"],\"__native-tls-alpn\":[\"native-tls-crate?/alpn\",\"hyper-tls?/alpn\"],\"__rustls\":[\"dep:hyper-rustls\",\"dep:tokio-rustls\",\"dep:rustls\",\"__tls\"],\"__rustls-aws-lc-rs\":[\"hyper-rustls?/aws-lc-rs\",\"tokio-rustls?/aws-lc-rs\",\"rustls?/aws-lc-rs\",\"quinn?/rustls-aws-lc-rs\"],\"__tls\":[\"dep:rustls-pki-types\",\"tokio/io-util\"],\"blocking\":[\"dep:futures-channel\",\"futures-channel?/sink\",\"dep:futures-util\",\"futures-util?/io\",\"futures-util?/sink\",\"tokio/sync\"],\"brotli\":[\"tower-http/decompression-br\"],\"charset\":[\"dep:encoding_rs\",\"dep:mime\"],\"cookies\":[\"dep:cookie_crate\",\"dep:cookie_store\"],\"default\":[\"default-tls\",\"charset\",\"http2\",\"system-proxy\"],\"default-tls\":[\"rustls\"],\"deflate\":[\"tower-http/decompression-deflate\"],\"form\":[\"dep:serde\",\"dep:serde_urlencoded\"],\"gzip\":[\"tower-http/decompression-gzip\"],\"hickory-dns\":[\"dep:hickory-resolver\",\"dep:once_cell\"],\"http2\":[\"dep:h2\",\"hyper/http2\",\"hyper-util/http2\",\"hyper-rustls?/http2\"],\"http3\":[\"rustls\",\"dep:h3\",\"dep:h3-quinn\",\"dep:quinn\",\"tokio/macros\"],\"json\":[\"dep:serde\",\"dep:serde_json\"],\"multipart\":[\"dep:mime_guess\",\"dep:futures-util\"],\"native-tls\":[\"__native-tls\",\"__native-tls-alpn\"],\"native-tls-no-alpn\":[\"__native-tls\"],\"native-tls-vendored\":[\"__native-tls\",\"native-tls-crate?/vendored\",\"__native-tls-alpn\"],\"native-tls-vendored-no-alpn\":[\"__native-tls\",\"native-tls-crate?/vendored\"],\"query\":[\"dep:serde\",\"dep:serde_urlencoded\"],\"rustls\":[\"__rustls-aws-lc-rs\",\"dep:rustls-platform-verifier\",\"__rustls\"],\"rustls-no-provider\":[\"dep:rustls-platform-verifier\",\"__rustls\"],\"socks\":[],\"stream\":[\"tokio/fs\",\"dep:futures-util\",\"dep:tokio-util\",\"dep:wasm-streams\"],\"system-proxy\":[\"hyper-util/client-proxy-system\"],\"zstd\":[\"tower-http/decompression-zstd\"]}}", "resolv-conf_0.7.6": "{\"dependencies\":[],\"features\":{\"system\":[]}}", "rfc6979_0.4.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"reset\"],\"name\":\"hmac\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2\"}],\"features\":{}}", "ring_0.17.14": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.2.8\"},{\"default_features\":false,\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"getrandom\",\"req\":\"^0.2.10\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(all(any(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), all(target_arch = \\\"arm\\\", target_endian = \\\"little\\\")), any(target_os = \\\"android\\\", target_os = \\\"linux\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_vendor = \\\"apple\\\", any(target_os = \\\"ios\\\", target_os = \\\"macos\\\", target_os = \\\"tvos\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\")))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.37\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\"^0.52\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_os = \\\"windows\\\"))\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\",\"dev_urandom_fallback\"],\"dev_urandom_fallback\":[],\"less-safe-getrandom-custom-or-rdrand\":[],\"less-safe-getrandom-espidf\":[],\"slow_tests\":[],\"std\":[\"alloc\"],\"test_logging\":[],\"unstable-testing-arm-no-hw\":[],\"unstable-testing-arm-no-neon\":[],\"wasm32_unknown_unknown_js\":[\"getrandom/js\"]}}", "rlimit_0.10.2": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.147\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.18.0\"}],\"features\":{}}", + "rouille_3.6.2": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.13\"},{\"name\":\"brotli\",\"optional\":true,\"req\":\"^3.3.2\"},{\"default_features\":false,\"features\":[\"clock\"],\"name\":\"chrono\",\"req\":\"^0.4.19\"},{\"features\":[\"gzip\"],\"name\":\"deflate\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"filetime\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"server\"],\"name\":\"multipart\",\"req\":\"^0.18\"},{\"name\":\"percent-encoding\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"postgres\",\"req\":\"^0.19\"},{\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_derive\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"sha1_smol\",\"req\":\"^1.0.0\"},{\"name\":\"threadpool\",\"req\":\"^1\"},{\"features\":[\"local-offset\"],\"name\":\"time\",\"req\":\"^0.3.15\"},{\"default_features\":false,\"name\":\"tiny_http\",\"req\":\"^0.12.0\"},{\"name\":\"url\",\"req\":\"^2\"}],\"features\":{\"default\":[\"gzip\",\"brotli\"],\"gzip\":[\"deflate\"],\"rustls\":[\"tiny_http/ssl-rustls\"],\"ssl\":[\"tiny_http/ssl\"]}}", "roxmltree_0.14.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.5\"},{\"name\":\"xmlparser\",\"req\":\"^0.13.3\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "rsa_0.9.10": "{\"dependencies\":[{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"base64ct\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"const-oid\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"alloc\",\"oid\"],\"name\":\"digest\",\"req\":\"^0.10.5\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4.1\"},{\"default_features\":false,\"features\":[\"i128\",\"prime\",\"zeroize\"],\"name\":\"num-bigint\",\"package\":\"num-bigint-dig\",\"req\":\"^0.8.6\"},{\"default_features\":false,\"name\":\"num-integer\",\"req\":\"^0.1.39\"},{\"default_features\":false,\"features\":[\"libm\"],\"name\":\"num-traits\",\"req\":\"^0.2.9\"},{\"default_features\":false,\"features\":[\"alloc\",\"pkcs8\"],\"name\":\"pkcs1\",\"req\":\"^0.7.5\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"pkcs8\",\"req\":\"^0.10.2\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand_chacha\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6.4\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.184\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.89\"},{\"default_features\":false,\"features\":[\"oid\"],\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10.5\"},{\"default_features\":false,\"features\":[\"oid\"],\"kind\":\"dev\",\"name\":\"sha1\",\"req\":\"^0.10.5\"},{\"default_features\":false,\"features\":[\"oid\"],\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10.6\"},{\"default_features\":false,\"features\":[\"oid\"],\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10.6\"},{\"default_features\":false,\"features\":[\"oid\"],\"kind\":\"dev\",\"name\":\"sha3\",\"req\":\"^0.10.7\"},{\"default_features\":false,\"features\":[\"alloc\",\"digest\",\"rand_core\"],\"name\":\"signature\",\"req\":\">2.0, <2.3\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"spki\",\"req\":\"^0.7.3\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.1.1\"},{\"features\":[\"alloc\"],\"name\":\"zeroize\",\"req\":\"^1.5\"}],\"features\":{\"default\":[\"std\",\"pem\",\"u64_digit\"],\"getrandom\":[\"rand_core/getrandom\"],\"hazmat\":[],\"nightly\":[\"num-bigint/nightly\"],\"pem\":[\"pkcs1/pem\",\"pkcs8/pem\"],\"pkcs5\":[\"pkcs8/encryption\"],\"serde\":[\"dep:serde\",\"num-bigint/serde\"],\"std\":[\"digest/std\",\"pkcs1/std\",\"pkcs8/std\",\"rand_core/std\",\"signature/std\"],\"u64_digit\":[\"num-bigint/u64_digit\"]}}", "rust_decimal_1.39.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"arrayvec\",\"req\":\"^0.7\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"derive\",\"unstable__schema\"],\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.1.1\"},{\"default_features\":false,\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"bytes\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"csv\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"diesel\",\"optional\":true,\"req\":\"^2.2.3\"},{\"default_features\":false,\"features\":[\"mysql\",\"postgres\"],\"kind\":\"dev\",\"name\":\"diesel\",\"req\":\"^2.2.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"ndarray\",\"optional\":true,\"req\":\"^0.15.6\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"postgres\",\"req\":\"^0.19\"},{\"default_features\":false,\"name\":\"postgres-types\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"proptest\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"getrandom\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand-0_9\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"thread_rng\"],\"kind\":\"dev\",\"name\":\"rand-0_9\",\"package\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"size_32\",\"std\"],\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.42\"},{\"kind\":\"dev\",\"name\":\"rkyv-0_8\",\"package\":\"rkyv\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rocket\",\"optional\":true,\"req\":\"^0.5.0-rc.3\"},{\"default_features\":false,\"name\":\"rust_decimal_macros\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"tokio-postgres\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"tokio-postgres\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"html_root_url_updated\",\"markdown_deps_updated\"],\"kind\":\"dev\",\"name\":\"version-sync\",\"req\":\"^0.9\"}],\"features\":{\"align16\":[],\"borsh\":[\"dep:borsh\",\"std\"],\"c-repr\":[],\"db-diesel-mysql\":[\"diesel/mysql_backend\",\"std\"],\"db-diesel-postgres\":[\"diesel/postgres_backend\",\"std\"],\"db-diesel2-mysql\":[\"db-diesel-mysql\"],\"db-diesel2-postgres\":[\"db-diesel-postgres\"],\"db-postgres\":[\"dep:bytes\",\"dep:postgres-types\",\"std\"],\"db-tokio-postgres\":[\"dep:bytes\",\"dep:postgres-types\",\"std\"],\"default\":[\"serde\",\"std\"],\"legacy-ops\":[],\"macros\":[\"dep:rust_decimal_macros\"],\"maths\":[],\"maths-nopanic\":[\"maths\"],\"ndarray\":[\"dep:ndarray\"],\"proptest\":[\"dep:proptest\"],\"rand\":[\"dep:rand\"],\"rkyv\":[\"dep:rkyv\"],\"rkyv-safe\":[\"rkyv/validation\"],\"rocket-traits\":[\"dep:rocket\",\"std\"],\"rust-fuzz\":[\"dep:arbitrary\"],\"serde\":[\"dep:serde\"],\"serde-arbitrary-precision\":[\"serde-with-arbitrary-precision\"],\"serde-bincode\":[\"serde-str\"],\"serde-float\":[\"serde-with-float\"],\"serde-str\":[\"serde-with-str\"],\"serde-with-arbitrary-precision\":[\"serde\",\"serde_json/arbitrary_precision\",\"serde_json/std\"],\"serde-with-float\":[\"serde\"],\"serde-with-str\":[\"serde\"],\"std\":[\"arrayvec/std\",\"borsh?/std\",\"bytes?/std\",\"rand?/std\",\"rkyv?/std\",\"serde?/std\",\"serde_json?/std\"],\"tokio-pg\":[\"db-tokio-postgres\"]}}", - "rustc-hash_2.1.1": "{\"dependencies\":[{\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"nightly\":[],\"rand\":[\"dep:rand\",\"std\"],\"std\":[]}}", + "rustc-demangle_0.1.27": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"compiler_builtins\":[],\"rustc-dep-of-std\":[\"core\"],\"std\":[]}}", "rustc_version_0.4.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"semver\",\"req\":\"^1.0\"}],\"features\":{}}", "rustc_version_runtime_0.3.0": "{\"dependencies\":[{\"name\":\"rustc_version\",\"req\":\"^0.4.0\"},{\"kind\":\"build\",\"name\":\"rustc_version\",\"req\":\"^0.4.0\"},{\"name\":\"semver\",\"req\":\"^1.0\"},{\"kind\":\"build\",\"name\":\"semver\",\"req\":\"^1.0\"}],\"features\":{}}", "rustix_1.1.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\",\"target\":\"cfg(all(criterion, not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.171\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.171\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.171\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"name\":\"libc_errno\",\"optional\":true,\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\"},{\"default_features\":false,\"features\":[\"general\",\"ioctl\",\"no_std\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.11.0\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"features\":[\"auxvec\",\"general\",\"errno\",\"ioctl\",\"no_std\",\"elf\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.11.0\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.20.3\",\"target\":\"cfg(windows)\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"all-apis\":[\"event\",\"fs\",\"io_uring\",\"mm\",\"mount\",\"net\",\"param\",\"pipe\",\"process\",\"pty\",\"rand\",\"runtime\",\"shm\",\"stdio\",\"system\",\"termios\",\"thread\",\"time\"],\"alloc\":[],\"default\":[\"std\"],\"event\":[],\"fs\":[],\"io_uring\":[\"event\",\"fs\",\"net\",\"thread\",\"linux-raw-sys/io_uring\"],\"linux_4_11\":[],\"linux_5_1\":[\"linux_4_11\"],\"linux_5_11\":[\"linux_5_1\"],\"linux_latest\":[\"linux_5_11\"],\"mm\":[],\"mount\":[],\"net\":[\"linux-raw-sys/net\",\"linux-raw-sys/netlink\",\"linux-raw-sys/if_ether\",\"linux-raw-sys/xdp\"],\"param\":[],\"pipe\":[],\"process\":[\"linux-raw-sys/prctl\"],\"pty\":[\"fs\"],\"rand\":[],\"runtime\":[\"linux-raw-sys/prctl\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\",\"linux-raw-sys/rustc-dep-of-std\",\"bitflags/rustc-dep-of-std\"],\"shm\":[\"fs\"],\"std\":[\"bitflags/std\",\"alloc\",\"libc?/std\",\"libc_errno?/std\"],\"stdio\":[],\"system\":[\"linux-raw-sys/system\"],\"termios\":[],\"thread\":[\"linux-raw-sys/prctl\"],\"time\":[],\"try_close\":[],\"use-explicitly-provided-auxv\":[],\"use-libc\":[\"libc_errno\",\"libc\"],\"use-libc-auxv\":[]}}", "rustix_1.1.4": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\",\"target\":\"cfg(all(criterion, not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.182\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.171\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"name\":\"libc_errno\",\"optional\":true,\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\"},{\"default_features\":false,\"features\":[\"general\",\"ioctl\",\"no_std\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.12\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"features\":[\"auxvec\",\"general\",\"errno\",\"ioctl\",\"no_std\",\"elf\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.12\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.20.3\",\"target\":\"cfg(windows)\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"all-apis\":[\"event\",\"fs\",\"io_uring\",\"mm\",\"mount\",\"net\",\"param\",\"pipe\",\"process\",\"pty\",\"rand\",\"runtime\",\"shm\",\"stdio\",\"system\",\"termios\",\"thread\",\"time\"],\"alloc\":[],\"default\":[\"std\"],\"event\":[],\"fs\":[],\"io_uring\":[\"event\",\"fs\",\"net\",\"thread\",\"linux-raw-sys/io_uring\"],\"linux_4_11\":[],\"linux_5_1\":[\"linux_4_11\"],\"linux_5_11\":[\"linux_5_1\"],\"linux_latest\":[\"linux_5_11\"],\"mm\":[],\"mount\":[],\"net\":[\"linux-raw-sys/net\",\"linux-raw-sys/netlink\",\"linux-raw-sys/if_ether\",\"linux-raw-sys/xdp\"],\"param\":[],\"pipe\":[],\"process\":[\"linux-raw-sys/prctl\"],\"pty\":[\"fs\"],\"rand\":[],\"runtime\":[\"linux-raw-sys/prctl\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\",\"linux-raw-sys/rustc-dep-of-std\",\"bitflags/rustc-dep-of-std\"],\"shm\":[\"fs\"],\"std\":[\"bitflags/std\",\"alloc\",\"libc?/std\",\"libc_errno?/std\"],\"stdio\":[],\"system\":[\"linux-raw-sys/system\"],\"termios\":[],\"thread\":[\"linux-raw-sys/prctl\"],\"time\":[],\"try_close\":[],\"use-explicitly-provided-auxv\":[],\"use-libc\":[\"libc_errno\",\"libc\"],\"use-libc-auxv\":[]}}", "rustls-native-certs_0.8.2": "{\"dependencies\":[{\"name\":\"openssl-probe\",\"req\":\"^0.1.6\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"features\":[\"std\"],\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.10\"},{\"kind\":\"dev\",\"name\":\"ring\",\"req\":\"^0.17\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"kind\":\"dev\",\"name\":\"rustls-webpki\",\"req\":\"^0.103\"},{\"name\":\"schannel\",\"req\":\"^0.1\",\"target\":\"cfg(windows)\"},{\"name\":\"security-framework\",\"req\":\"^3\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5\"},{\"kind\":\"dev\",\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17\"}],\"features\":{}}", "rustls-pki-types_1.13.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"crabgrind\",\"req\":\"=0.1.9\",\"target\":\"cfg(all(target_os = \\\"linux\\\", target_arch = \\\"x86_64\\\"))\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"dep:zeroize\"],\"default\":[\"alloc\"],\"std\":[\"alloc\"],\"web\":[\"web-time\"]}}", + "rustls-pki-types_1.14.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"crabgrind\",\"req\":\"=0.1.9\",\"target\":\"cfg(all(target_os = \\\"linux\\\", target_arch = \\\"x86_64\\\"))\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"dep:zeroize\"],\"default\":[\"alloc\"],\"std\":[\"alloc\"],\"web\":[\"web-time\"]}}", "rustls-platform-verifier-android_0.1.1": "{\"dependencies\":[],\"features\":{}}", "rustls-platform-verifier_0.6.2": "{\"dependencies\":[{\"name\":\"android_logger\",\"optional\":true,\"req\":\"^0.15\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"core-foundation\",\"req\":\"^0.10\",\"target\":\"cfg(any(target_vendor = \\\"apple\\\"))\"},{\"name\":\"core-foundation-sys\",\"req\":\"^0.8\",\"target\":\"cfg(any(target_vendor = \\\"apple\\\"))\"},{\"default_features\":false,\"name\":\"jni\",\"req\":\"^0.21\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"default_features\":false,\"name\":\"jni\",\"optional\":true,\"req\":\"^0.21\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"req\":\"^1.9\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.9\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"req\":\"^0.23.27\"},{\"default_features\":false,\"features\":[\"ring\"],\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"name\":\"rustls-native-certs\",\"req\":\"^0.8\",\"target\":\"cfg(all(unix, not(target_os = \\\"android\\\"), not(target_vendor = \\\"apple\\\"), not(target_arch = \\\"wasm32\\\")))\"},{\"name\":\"rustls-platform-verifier-android\",\"req\":\"^0.1.0\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"security-framework\",\"req\":\"^3.5.0\",\"target\":\"cfg(any(target_vendor = \\\"apple\\\"))\"},{\"name\":\"security-framework-sys\",\"req\":\"^2.15\",\"target\":\"cfg(any(target_vendor = \\\"apple\\\"))\"},{\"default_features\":false,\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\",\"target\":\"cfg(all(unix, not(target_os = \\\"android\\\"), not(target_vendor = \\\"apple\\\"), not(target_arch = \\\"wasm32\\\")))\"},{\"default_features\":false,\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"webpki-root-certs\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"webpki-root-certs\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_Security_Cryptography\"],\"name\":\"windows-sys\",\"req\":\">=0.52.0, <0.62.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"cert-logging\":[\"base64\"],\"dbg\":[],\"docsrs\":[\"jni\",\"once_cell\"],\"ffi-testing\":[\"android_logger\",\"rustls/ring\"]}}", "rustls-webpki_0.103.13": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.14\"},{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"kind\":\"dev\",\"name\":\"bzip2\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.17.2\"},{\"default_features\":false,\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.12\"},{\"default_features\":false,\"features\":[\"aws_lc_rs\"],\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14.2\"},{\"default_features\":false,\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.18.1\"}],\"features\":{\"alloc\":[\"ring?/alloc\",\"pki-types/alloc\"],\"aws-lc-rs\":[\"dep:aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/prebuilt-nasm\"],\"aws-lc-rs-fips\":[\"dep:aws-lc-rs\",\"aws-lc-rs/fips\"],\"aws-lc-rs-unstable\":[\"aws-lc-rs\",\"aws-lc-rs/unstable\"],\"default\":[\"std\"],\"ring\":[\"dep:ring\"],\"std\":[\"alloc\",\"pki-types/std\"]}}", "rustls_0.23.34": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.14\"},{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"brotli\",\"optional\":true,\"req\":\"^8\"},{\"name\":\"brotli-decompressor\",\"optional\":true,\"req\":\"^5.0.0\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"macro_rules_attribute\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"features\":[\"alloc\",\"race\"],\"name\":\"once_cell\",\"req\":\"^1.16\"},{\"features\":[\"alloc\"],\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.12\"},{\"default_features\":false,\"features\":[\"pem\",\"aws_lc_rs\"],\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14\"},{\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"kind\":\"build\",\"name\":\"rustversion\",\"optional\":true,\"req\":\"^1.0.6\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103.5\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17\"},{\"name\":\"zeroize\",\"req\":\"^1.8\"},{\"name\":\"zlib-rs\",\"optional\":true,\"req\":\"^0.5\"}],\"features\":{\"aws-lc-rs\":[\"aws_lc_rs\"],\"aws_lc_rs\":[\"dep:aws-lc-rs\",\"webpki/aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/prebuilt-nasm\"],\"brotli\":[\"dep:brotli\",\"dep:brotli-decompressor\",\"std\"],\"custom-provider\":[],\"default\":[\"aws_lc_rs\",\"logging\",\"prefer-post-quantum\",\"std\",\"tls12\"],\"fips\":[\"aws_lc_rs\",\"aws-lc-rs?/fips\",\"webpki/aws-lc-rs-fips\"],\"logging\":[\"log\"],\"prefer-post-quantum\":[\"aws_lc_rs\"],\"read_buf\":[\"rustversion\",\"std\"],\"ring\":[\"dep:ring\",\"webpki/ring\"],\"std\":[\"webpki/std\",\"pki-types/std\",\"once_cell/std\"],\"tls12\":[],\"zlib\":[\"dep:zlib-rs\"]}}", + "rustls_0.23.40": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.14\"},{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"brotli\",\"optional\":true,\"req\":\"^8\"},{\"name\":\"brotli-decompressor\",\"optional\":true,\"req\":\"^5.0.0\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"macro_rules_attribute\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"features\":[\"alloc\",\"race\"],\"name\":\"once_cell\",\"req\":\"^1.16\"},{\"features\":[\"alloc\"],\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.12\"},{\"default_features\":false,\"features\":[\"pem\",\"aws_lc_rs\"],\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14\"},{\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"kind\":\"build\",\"name\":\"rustversion\",\"optional\":true,\"req\":\"^1.0.6\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103.5\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17\"},{\"name\":\"zeroize\",\"req\":\"^1.8\"},{\"name\":\"zlib-rs\",\"optional\":true,\"req\":\"^0.6\"}],\"features\":{\"aws-lc-rs\":[\"aws_lc_rs\"],\"aws_lc_rs\":[\"dep:aws-lc-rs\",\"webpki/aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/prebuilt-nasm\"],\"brotli\":[\"dep:brotli\",\"dep:brotli-decompressor\",\"std\"],\"custom-provider\":[],\"default\":[\"aws_lc_rs\",\"logging\",\"prefer-post-quantum\",\"std\",\"tls12\"],\"fips\":[\"aws_lc_rs\",\"aws-lc-rs?/fips\",\"webpki/aws-lc-rs-fips\"],\"logging\":[\"log\"],\"prefer-post-quantum\":[\"aws_lc_rs\"],\"read_buf\":[\"rustversion\",\"std\"],\"ring\":[\"dep:ring\",\"webpki/ring\"],\"std\":[\"webpki/std\",\"pki-types/std\",\"once_cell/std\"],\"tls12\":[],\"zlib\":[\"dep:zlib-rs\"]}}", "rustversion_1.0.22": "{\"dependencies\":[{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.49\"}],\"features\":{}}", "ryu_1.0.23": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.5\"}],\"features\":{\"small\":[]}}", + "safemem_0.3.3": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "same-file_1.0.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"winapi-util\",\"req\":\"^0.1.1\",\"target\":\"cfg(windows)\"}],\"features\":{}}", - "scc_2.4.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.7\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"name\":\"sdd\",\"req\":\"^3.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.47\"}],\"features\":{\"loom\":[\"dep:loom\",\"sdd/loom\"]}}", "schannel_0.1.28": "{\"dependencies\":[{\"features\":[\"Win32_Foundation\",\"Win32_Security_Cryptography\",\"Win32_Security_Authentication_Identity\",\"Win32_Security_Credentials\",\"Win32_System_LibraryLoader\",\"Win32_System_Memory\",\"Win32_System_SystemInformation\"],\"name\":\"windows-sys\",\"req\":\"^0.61\"},{\"features\":[\"Win32_System_SystemInformation\",\"Win32_System_Time\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\"}],\"features\":{}}", "schemars_0.9.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arrayvec07\",\"optional\":true,\"package\":\"arrayvec\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"arrayvec07\",\"package\":\"arrayvec\",\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"bigdecimal04\",\"optional\":true,\"package\":\"bigdecimal\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bigdecimal04\",\"package\":\"bigdecimal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"bytes1\",\"optional\":true,\"package\":\"bytes\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bytes1\",\"package\":\"bytes\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"chrono04\",\"optional\":true,\"package\":\"chrono\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono04\",\"package\":\"chrono\",\"req\":\"^0.4\"},{\"name\":\"dyn-clone\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"either1\",\"optional\":true,\"package\":\"either\",\"req\":\"^1.3\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"either1\",\"package\":\"either\",\"req\":\"^1.3\"},{\"features\":[\"derive\",\"email\",\"regex\",\"url\"],\"kind\":\"dev\",\"name\":\"garde\",\"req\":\"^0.22\"},{\"default_features\":false,\"name\":\"indexmap2\",\"optional\":true,\"package\":\"indexmap\",\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"indexmap2\",\"package\":\"indexmap\",\"req\":\"^2.0\"},{\"default_features\":false,\"name\":\"jiff02\",\"optional\":true,\"package\":\"jiff\",\"req\":\"^0.2\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"jiff02\",\"package\":\"jiff\",\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"jsonschema\",\"req\":\"^0.30\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.2.1\"},{\"name\":\"ref-cast\",\"req\":\"^1.0.22\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.10.6\"},{\"default_features\":false,\"name\":\"rust_decimal1\",\"optional\":true,\"package\":\"rust_decimal\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"rust_decimal1\",\"package\":\"rust_decimal\",\"req\":\"^1\"},{\"name\":\"schemars_derive\",\"optional\":true,\"req\":\"=0.9.0\"},{\"default_features\":false,\"name\":\"semver1\",\"optional\":true,\"package\":\"semver\",\"req\":\"^1.0.9\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"semver1\",\"package\":\"semver\",\"req\":\"^1.0.9\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde_json\",\"req\":\"^1.0.127\"},{\"kind\":\"dev\",\"name\":\"serde_repr\",\"req\":\"^0.1.19\"},{\"default_features\":false,\"name\":\"smallvec1\",\"optional\":true,\"package\":\"smallvec\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"smallvec1\",\"package\":\"smallvec\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"smol_str02\",\"optional\":true,\"package\":\"smol_str\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"smol_str02\",\"package\":\"smol_str\",\"req\":\"^0.2.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.17\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"url2\",\"optional\":true,\"package\":\"url\",\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"serde\",\"std\"],\"kind\":\"dev\",\"name\":\"url2\",\"package\":\"url\",\"req\":\"^2.0\"},{\"default_features\":false,\"name\":\"uuid1\",\"optional\":true,\"package\":\"uuid\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"uuid1\",\"package\":\"uuid\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"validator\",\"req\":\"^0.20\"}],\"features\":{\"_ui_test\":[],\"default\":[\"derive\",\"std\"],\"derive\":[\"schemars_derive\"],\"preserve_order\":[\"serde_json/preserve_order\"],\"raw_value\":[\"serde_json/raw_value\"],\"std\":[]}}", "schemars_1.2.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arrayvec07\",\"optional\":true,\"package\":\"arrayvec\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"arrayvec07\",\"package\":\"arrayvec\",\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"bigdecimal04\",\"optional\":true,\"package\":\"bigdecimal\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bigdecimal04\",\"package\":\"bigdecimal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"bytes1\",\"optional\":true,\"package\":\"bytes\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bytes1\",\"package\":\"bytes\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"chrono04\",\"optional\":true,\"package\":\"chrono\",\"req\":\"^0.4.39\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono04\",\"package\":\"chrono\",\"req\":\"^0.4\"},{\"name\":\"dyn-clone\",\"req\":\"^1.0.17\"},{\"default_features\":false,\"name\":\"either1\",\"optional\":true,\"package\":\"either\",\"req\":\"^1.3\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"either1\",\"package\":\"either\",\"req\":\"^1.3\"},{\"features\":[\"derive\",\"email\",\"regex\",\"url\"],\"kind\":\"dev\",\"name\":\"garde\",\"req\":\"^0.22\"},{\"default_features\":false,\"name\":\"indexmap2\",\"optional\":true,\"package\":\"indexmap\",\"req\":\"^2.2.3\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"indexmap2\",\"package\":\"indexmap\",\"req\":\"^2.0\"},{\"default_features\":false,\"name\":\"jiff02\",\"optional\":true,\"package\":\"jiff\",\"req\":\"^0.2\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"jiff02\",\"package\":\"jiff\",\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"jsonschema\",\"req\":\"^0.30\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.2.1\"},{\"name\":\"ref-cast\",\"req\":\"^1.0.22\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.10.6\"},{\"default_features\":false,\"name\":\"rust_decimal1\",\"optional\":true,\"package\":\"rust_decimal\",\"req\":\"^1.13\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"rust_decimal1\",\"package\":\"rust_decimal\",\"req\":\"^1\"},{\"name\":\"schemars_derive\",\"optional\":true,\"req\":\"=1.2.1\"},{\"default_features\":false,\"name\":\"semver1\",\"optional\":true,\"package\":\"semver\",\"req\":\"^1.0.9\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"semver1\",\"package\":\"semver\",\"req\":\"^1.0.9\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"req\":\"^1.0.194\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde_json\",\"req\":\"^1.0.127\"},{\"kind\":\"dev\",\"name\":\"serde_repr\",\"req\":\"^0.1.19\"},{\"default_features\":false,\"name\":\"smallvec1\",\"optional\":true,\"package\":\"smallvec\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"smallvec1\",\"package\":\"smallvec\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"smol_str02\",\"optional\":true,\"package\":\"smol_str\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"smol_str02\",\"package\":\"smol_str\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"name\":\"smol_str03\",\"optional\":true,\"package\":\"smol_str\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"smol_str03\",\"package\":\"smol_str\",\"req\":\"^0.3.2\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.17\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"url2\",\"optional\":true,\"package\":\"url\",\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"serde\",\"std\"],\"kind\":\"dev\",\"name\":\"url2\",\"package\":\"url\",\"req\":\"^2.0\"},{\"default_features\":false,\"name\":\"uuid1\",\"optional\":true,\"package\":\"uuid\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"uuid1\",\"package\":\"uuid\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"validator\",\"req\":\"^0.20\"}],\"features\":{\"_ui_test\":[],\"default\":[\"derive\",\"std\"],\"derive\":[\"schemars_derive\"],\"preserve_order\":[\"serde_json/preserve_order\"],\"raw_value\":[\"serde_json/raw_value\"],\"std\":[]}}", @@ -1221,11 +1132,11 @@ "scopeguard_1.2.0": "{\"dependencies\":[],\"features\":{\"default\":[\"use_std\"],\"use_std\":[]}}", "scroll_0.13.0": "{\"dependencies\":[{\"name\":\"scroll_derive\",\"optional\":true,\"req\":\"^0.13\"}],\"features\":{\"default\":[\"std\"],\"derive\":[\"dep:scroll_derive\"],\"std\":[]}}", "scroll_derive_0.13.1": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"scroll\",\"req\":\"^0.13\"},{\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", - "sdd_3.0.10": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.6\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"}],\"features\":{}}", "sec1_0.7.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"base16ct\",\"optional\":true,\"req\":\"^0.2\"},{\"features\":[\"oid\"],\"name\":\"der\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"generic-array\",\"optional\":true,\"req\":\"^0.14.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"pkcs8\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"subtle\",\"optional\":true,\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"der?/alloc\",\"pkcs8?/alloc\",\"zeroize?/alloc\"],\"default\":[\"der\",\"point\"],\"der\":[\"dep:der\",\"zeroize\"],\"pem\":[\"alloc\",\"der/pem\",\"pkcs8/pem\"],\"point\":[\"dep:base16ct\",\"dep:generic-array\"],\"serde\":[\"dep:serdect\"],\"std\":[\"alloc\",\"der?/std\"],\"zeroize\":[\"dep:zeroize\",\"der?/zeroize\"]}}", "security-framework-sys_2.15.0": "{\"dependencies\":[{\"name\":\"core-foundation-sys\",\"req\":\"^0.8.6\"},{\"name\":\"libc\",\"req\":\"^0.2.150\"}],\"features\":{\"OSX_10_10\":[\"OSX_10_9\"],\"OSX_10_11\":[\"OSX_10_10\"],\"OSX_10_12\":[\"OSX_10_11\"],\"OSX_10_13\":[\"OSX_10_12\"],\"OSX_10_14\":[\"OSX_10_13\"],\"OSX_10_15\":[\"OSX_10_14\"],\"OSX_10_9\":[],\"default\":[\"OSX_10_12\"]}}", "security-framework_3.5.1": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.6\"},{\"name\":\"core-foundation\",\"req\":\"^0.10\"},{\"name\":\"core-foundation-sys\",\"req\":\"^0.8.6\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"libc\",\"req\":\"^0.2.139\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"name\":\"security-framework-sys\",\"req\":\"^2.15\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.12.0\"},{\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.23\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.16\"}],\"features\":{\"OSX_10_12\":[\"security-framework-sys/OSX_10_12\"],\"OSX_10_13\":[\"OSX_10_12\",\"security-framework-sys/OSX_10_13\",\"alpn\",\"session-tickets\"],\"OSX_10_14\":[\"OSX_10_13\",\"security-framework-sys/OSX_10_14\"],\"OSX_10_15\":[\"OSX_10_14\",\"security-framework-sys/OSX_10_15\"],\"alpn\":[],\"default\":[\"OSX_10_12\"],\"job-bless\":[],\"nightly\":[],\"session-tickets\":[],\"sync-keychain\":[\"OSX_10_13\"]}}", "semver_1.0.27": "{\"dependencies\":[{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"package\":\"serde_core\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde\"],\"std\":[]}}", + "semver_1.0.28": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"package\":\"serde_core\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde\"],\"std\":[]}}", "separator_0.4.1": "{\"dependencies\":[],\"features\":{}}", "serde_1.0.228": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"result\"],\"name\":\"serde_core\",\"req\":\"=1.0.228\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"default\":[\"std\"],\"derive\":[\"serde_derive\"],\"rc\":[\"serde_core/rc\"],\"std\":[\"serde_core/std\"],\"unstable\":[\"serde_core/unstable\"]}}", "serde_bytes_0.11.19": "{\"dependencies\":[{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.166\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"default\":[\"std\"],\"std\":[\"serde_core/std\"]}}", @@ -1233,24 +1144,26 @@ "serde_derive_1.0.228": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"derive\",\"parsing\",\"printing\",\"proc-macro\"],\"name\":\"syn\",\"req\":\"^2.0.81\"}],\"features\":{\"default\":[],\"deserialize_in_place\":[]}}", "serde_derive_internals_0.29.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"derive\",\"parsing\",\"printing\"],\"name\":\"syn\",\"req\":\"^2.0.46\"}],\"features\":{}}", "serde_json5_0.2.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"matches\",\"req\":\"^0.1.8\"},{\"name\":\"pest\",\"req\":\"^2.0\"},{\"name\":\"pest_derive\",\"req\":\"^2.0\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{}}", + "serde_json_1.0.145": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.11\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.3\"},{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2.0.2\"},{\"name\":\"itoa\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"name\":\"ryu\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.194\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.10\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.166\"},{\"kind\":\"dev\",\"name\":\"serde_stacker\",\"req\":\"^0.1.8\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"arbitrary_precision\":[],\"default\":[\"std\"],\"float_roundtrip\":[],\"preserve_order\":[\"indexmap\",\"std\"],\"raw_value\":[],\"std\":[\"memchr/std\",\"serde_core/std\"],\"unbounded_depth\":[]}}", "serde_json_1.0.149": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.11\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.3\"},{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2.0.2\"},{\"name\":\"itoa\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.194\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.10\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.166\"},{\"kind\":\"dev\",\"name\":\"serde_stacker\",\"req\":\"^0.1.8\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"},{\"name\":\"zmij\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"arbitrary_precision\":[],\"default\":[\"std\"],\"float_roundtrip\":[],\"preserve_order\":[\"indexmap\",\"std\"],\"raw_value\":[],\"std\":[\"memchr/std\",\"serde_core/std\"],\"unbounded_depth\":[]}}", "serde_json_1.0.150": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.11\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.3\"},{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2.0.2\"},{\"name\":\"itoa\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.194\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.10\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.166\"},{\"kind\":\"dev\",\"name\":\"serde_stacker\",\"req\":\"^0.1.8\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"},{\"name\":\"zmij\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"arbitrary_precision\":[],\"default\":[\"std\"],\"float_roundtrip\":[],\"preserve_order\":[\"indexmap\",\"std\"],\"raw_value\":[],\"std\":[\"memchr/std\",\"serde_core/std\"],\"unbounded_depth\":[]}}", - "serde_qs_0.8.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"actix-web\",\"optional\":true,\"package\":\"actix-web\",\"req\":\"^3.3\"},{\"default_features\":false,\"name\":\"actix-web2\",\"optional\":true,\"package\":\"actix-web\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"csv\",\"req\":\"^1.1\"},{\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_urlencoded\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"serde_with\",\"req\":\"^1.10\"},{\"name\":\"thiserror\",\"req\":\"^1.0\"},{\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"warp-framework\",\"optional\":true,\"package\":\"warp\",\"req\":\"^0.3\"}],\"features\":{\"actix\":[\"actix-web\",\"futures\"],\"actix2\":[\"actix-web2\",\"futures\"],\"default\":[],\"warp\":[\"futures\",\"tracing\",\"warp-framework\"]}}", "serde_test_1.0.177": "{\"dependencies\":[{\"name\":\"serde\",\"req\":\"^1.0.69\"},{\"features\":[\"rc\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"}],\"features\":{}}", "serde_urlencoded_0.7.1": "{\"dependencies\":[{\"name\":\"form_urlencoded\",\"req\":\"^1\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"name\":\"ryu\",\"req\":\"^1\"},{\"name\":\"serde\",\"req\":\"^1.0.69\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"}],\"features\":{}}", - "serde_with_3.15.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"chrono_0_4\",\"optional\":true,\"package\":\"chrono\",\"req\":\"^0.4.20\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"expect-test\",\"req\":\"^1.5.1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.6\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3.3\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_14\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.14.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_15\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.15.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_16\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.16.0\"},{\"default_features\":false,\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4.3\"},{\"default_features\":false,\"features\":[\"serde-1\"],\"name\":\"indexmap_1\",\"optional\":true,\"package\":\"indexmap\",\"req\":\"^1.8\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"indexmap_2\",\"optional\":true,\"package\":\"indexmap\",\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"resolve-file\"],\"kind\":\"dev\",\"name\":\"jsonschema\",\"req\":\"^0.33.0\"},{\"kind\":\"dev\",\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.12.1\"},{\"kind\":\"dev\",\"name\":\"rmp-serde\",\"req\":\"^1.3.0\"},{\"kind\":\"dev\",\"name\":\"ron\",\"req\":\"^0.11\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"default_features\":false,\"name\":\"schemars_0_8\",\"optional\":true,\"package\":\"schemars\",\"req\":\"^0.8.16\"},{\"kind\":\"dev\",\"name\":\"schemars_0_8\",\"package\":\"schemars\",\"req\":\"^0.8.16\"},{\"default_features\":false,\"name\":\"schemars_0_9\",\"optional\":true,\"package\":\"schemars\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"schemars_0_9\",\"package\":\"schemars\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"schemars_1\",\"optional\":true,\"package\":\"schemars\",\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"schemars_1\",\"package\":\"schemars\",\"req\":\"^1.0.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.152\"},{\"kind\":\"dev\",\"name\":\"serde-xml-rs\",\"req\":\"^0.8.1\"},{\"default_features\":false,\"features\":[\"result\"],\"name\":\"serde_core\",\"req\":\"^1.0.225\"},{\"default_features\":false,\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.145\"},{\"features\":[\"preserve_order\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.124\"},{\"name\":\"serde_with_macros\",\"optional\":true,\"req\":\"=3.15.1\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.2\"},{\"default_features\":false,\"name\":\"time_0_3\",\"optional\":true,\"package\":\"time\",\"req\":\"~0.3.36\"}],\"features\":{\"alloc\":[\"serde_core/alloc\",\"base64?/alloc\",\"chrono_0_4?/alloc\",\"hex?/alloc\",\"serde_json?/alloc\",\"time_0_3?/alloc\"],\"base64\":[\"dep:base64\",\"alloc\"],\"chrono\":[\"chrono_0_4\"],\"chrono_0_4\":[\"dep:chrono_0_4\"],\"default\":[\"std\",\"macros\"],\"guide\":[\"dep:document-features\",\"macros\",\"std\"],\"hashbrown_0_14\":[\"dep:hashbrown_0_14\",\"alloc\"],\"hashbrown_0_15\":[\"dep:hashbrown_0_15\",\"alloc\"],\"hashbrown_0_16\":[\"dep:hashbrown_0_16\",\"alloc\"],\"hex\":[\"dep:hex\",\"alloc\"],\"indexmap\":[\"indexmap_1\"],\"indexmap_1\":[\"dep:indexmap_1\",\"alloc\"],\"indexmap_2\":[\"dep:indexmap_2\",\"alloc\"],\"json\":[\"dep:serde_json\",\"alloc\"],\"macros\":[\"dep:serde_with_macros\"],\"schemars_0_8\":[\"dep:schemars_0_8\",\"std\",\"serde_with_macros?/schemars_0_8\"],\"schemars_0_9\":[\"dep:schemars_0_9\",\"alloc\",\"serde_with_macros?/schemars_0_9\",\"dep:serde_json\"],\"schemars_1\":[\"dep:schemars_1\",\"alloc\",\"serde_with_macros?/schemars_1\",\"dep:serde_json\"],\"std\":[\"alloc\",\"serde_core/std\",\"chrono_0_4?/clock\",\"chrono_0_4?/std\",\"indexmap_1?/std\",\"indexmap_2?/std\",\"time_0_3?/serde-well-known\",\"time_0_3?/std\",\"schemars_0_9?/std\",\"schemars_1?/std\"],\"time_0_3\":[\"dep:time_0_3\"]}}", - "serde_with_macros_3.15.1": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.21.0\"},{\"kind\":\"dev\",\"name\":\"expect-test\",\"req\":\"^1.5.1\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3.3\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.1\"},{\"name\":\"quote\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.12.1\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.152\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.25\"},{\"features\":[\"extra-traits\",\"full\",\"parsing\"],\"name\":\"syn\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.111\"}],\"features\":{\"schemars_0_8\":[],\"schemars_0_9\":[],\"schemars_1\":[]}}", - "serial_test_3.2.0": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"env_logger\",\"optional\":true,\"req\":\">=0.6.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"fslock\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"executor\"],\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"use_std\"],\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\">=0.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\">=0.4.4\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"once_cell\",\"req\":\"^1.19\"},{\"default_features\":false,\"name\":\"parking_lot\",\"req\":\"^0.12\"},{\"default_features\":false,\"name\":\"scc\",\"req\":\"^2\"},{\"name\":\"serial_test_derive\",\"req\":\"~3.2.0\"}],\"features\":{\"async\":[\"dep:futures\",\"serial_test_derive/async\"],\"default\":[\"logging\",\"async\"],\"docsrs\":[\"dep:document-features\"],\"file_locks\":[\"dep:fslock\"],\"logging\":[\"dep:log\"],\"test_logging\":[\"logging\",\"dep:env_logger\",\"serial_test_derive/test_logging\"]}}", - "serial_test_derive_3.2.0": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\">=0.6.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"full\",\"printing\",\"parsing\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"async\":[],\"default\":[],\"test_logging\":[]}}", + "serde_with_3.21.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"default_features\":false,\"name\":\"bs58\",\"optional\":true,\"req\":\"^0.5.1\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"chrono_0_4\",\"optional\":true,\"package\":\"chrono\",\"req\":\"^0.4.20\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"expect-test\",\"req\":\"^1.5.1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.6\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3.3\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_14\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.14.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_15\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.15.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_16\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.16.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"hashbrown_0_17\",\"optional\":true,\"package\":\"hashbrown\",\"req\":\"^0.17.0\"},{\"default_features\":false,\"name\":\"hex\",\"optional\":true,\"req\":\"^0.4.3\"},{\"default_features\":false,\"features\":[\"serde-1\"],\"name\":\"indexmap_1\",\"optional\":true,\"package\":\"indexmap\",\"req\":\"^1.8\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"indexmap_2\",\"optional\":true,\"package\":\"indexmap\",\"req\":\"^2.0\"},{\"default_features\":false,\"features\":[\"resolve-file\"],\"kind\":\"dev\",\"name\":\"jsonschema\",\"req\":\"^0.33.0\"},{\"kind\":\"dev\",\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.12.1\"},{\"kind\":\"dev\",\"name\":\"rmp-serde\",\"req\":\"^1.3.0\"},{\"kind\":\"dev\",\"name\":\"ron\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"default_features\":false,\"name\":\"schemars_0_8\",\"optional\":true,\"package\":\"schemars\",\"req\":\"^0.8.16\"},{\"kind\":\"dev\",\"name\":\"schemars_0_8\",\"package\":\"schemars\",\"req\":\"^0.8.16\"},{\"default_features\":false,\"name\":\"schemars_0_9\",\"optional\":true,\"package\":\"schemars\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"schemars_0_9\",\"package\":\"schemars\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"schemars_1\",\"optional\":true,\"package\":\"schemars\",\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"schemars_1\",\"package\":\"schemars\",\"req\":\"^1.0.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.152\"},{\"kind\":\"dev\",\"name\":\"serde-xml-rs\",\"req\":\"^0.8.1\"},{\"default_features\":false,\"features\":[\"result\"],\"name\":\"serde_core\",\"req\":\"^1.0.225\"},{\"default_features\":false,\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.145\"},{\"features\":[\"preserve_order\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.124\"},{\"name\":\"serde_with_macros\",\"optional\":true,\"req\":\"=3.21.0\"},{\"default_features\":false,\"name\":\"smallvec_1\",\"optional\":true,\"package\":\"smallvec\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"time_0_3\",\"optional\":true,\"package\":\"time\",\"req\":\"~0.3.47\"},{\"kind\":\"dev\",\"name\":\"yaml_serde\",\"req\":\"^0.10.3\"}],\"features\":{\"alloc\":[\"serde_core/alloc\",\"base64?/alloc\",\"bs58?/alloc\",\"chrono_0_4?/alloc\",\"hex?/alloc\",\"serde_json?/alloc\",\"time_0_3?/alloc\"],\"base58\":[\"dep:bs58\",\"alloc\"],\"base64\":[\"dep:base64\",\"alloc\"],\"chrono\":[\"chrono_0_4\"],\"chrono_0_4\":[\"dep:chrono_0_4\"],\"default\":[\"std\",\"macros\"],\"guide\":[\"dep:document-features\",\"macros\",\"std\"],\"hashbrown_0_14\":[\"dep:hashbrown_0_14\",\"alloc\"],\"hashbrown_0_15\":[\"dep:hashbrown_0_15\",\"alloc\"],\"hashbrown_0_16\":[\"dep:hashbrown_0_16\",\"alloc\"],\"hashbrown_0_17\":[\"dep:hashbrown_0_17\",\"alloc\"],\"hex\":[\"dep:hex\",\"alloc\"],\"indexmap\":[\"indexmap_1\"],\"indexmap_1\":[\"dep:indexmap_1\",\"alloc\"],\"indexmap_2\":[\"dep:indexmap_2\",\"alloc\"],\"json\":[\"dep:serde_json\",\"alloc\"],\"macros\":[\"dep:serde_with_macros\"],\"schemars_0_8\":[\"dep:schemars_0_8\",\"std\",\"serde_with_macros?/schemars_0_8\",\"dep:serde_json\"],\"schemars_0_9\":[\"dep:schemars_0_9\",\"alloc\",\"serde_with_macros?/schemars_0_9\",\"dep:serde_json\"],\"schemars_1\":[\"dep:schemars_1\",\"alloc\",\"serde_with_macros?/schemars_1\",\"dep:serde_json\"],\"smallvec_1\":[\"dep:smallvec_1\"],\"std\":[\"alloc\",\"bs58?/std\",\"serde_core/std\",\"chrono_0_4?/clock\",\"chrono_0_4?/std\",\"indexmap_1?/std\",\"indexmap_2?/std\",\"time_0_3?/serde-well-known\",\"time_0_3?/std\",\"schemars_0_9?/std\",\"schemars_1?/std\"],\"time_0_3\":[\"dep:time_0_3\"]}}", + "serde_with_macros_3.21.0": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.23.0\"},{\"kind\":\"dev\",\"name\":\"expect-test\",\"req\":\"^1.5.1\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3.3\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.1\"},{\"name\":\"quote\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.12.1\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.152\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.25\"},{\"features\":[\"extra-traits\",\"full\",\"parsing\"],\"name\":\"syn\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.111\"}],\"features\":{\"schemars_0_8\":[],\"schemars_0_9\":[],\"schemars_1\":[]}}", + "serial_test_3.5.0": "{\"dependencies\":[{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"env_logger\",\"optional\":true,\"req\":\">=0.6.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"fslock\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-executor\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"use_std\"],\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\">=0.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\">=0.4.4\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"once_cell\",\"req\":\"^1.19\"},{\"default_features\":false,\"name\":\"parking_lot\",\"req\":\"^0.12\"},{\"name\":\"serial_test_derive\",\"req\":\"~3.5.0\"}],\"features\":{\"async\":[\"dep:futures-executor\",\"dep:futures-util\",\"serial_test_derive/async\"],\"default\":[\"logging\",\"async\"],\"docsrs\":[\"dep:document-features\"],\"file_locks\":[\"dep:fslock\"],\"logging\":[\"dep:log\"],\"test_logging\":[\"logging\",\"dep:env_logger\",\"serial_test_derive/test_logging\"]}}", + "serial_test_derive_3.5.0": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\">=0.6.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"full\",\"printing\",\"parsing\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"async\":[],\"default\":[],\"file_locks\":[],\"test_logging\":[]}}", "sha1_0.10.6": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"},{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"},{\"name\":\"sha1-asm\",\"optional\":true,\"req\":\"^0.5\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\"}],\"features\":{\"asm\":[\"sha1-asm\"],\"compress\":[],\"default\":[\"std\"],\"force-soft\":[],\"loongarch64_asm\":[],\"oid\":[\"digest/oid\"],\"std\":[\"digest/std\"]}}", "sha1_smol_1.0.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"openssl\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.4\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"std\":[\"alloc\"]}}", "sha2_0.10.9": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"cpufeatures\",\"req\":\"^0.2\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"},{\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"digest\",\"req\":\"^0.10.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.2.2\"},{\"name\":\"sha2-asm\",\"optional\":true,\"req\":\"^0.6.1\",\"target\":\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"}],\"features\":{\"asm\":[\"sha2-asm\"],\"asm-aarch64\":[\"asm\"],\"compress\":[],\"default\":[\"std\"],\"force-soft\":[],\"force-soft-compact\":[],\"loongarch64_asm\":[],\"oid\":[\"digest/oid\"],\"std\":[\"digest/std\"]}}", "sharded-slab_0.1.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"indexmap\",\"req\":\"^1\"},{\"name\":\"lazy_static\",\"req\":\"^1\"},{\"features\":[\"checkpoint\"],\"name\":\"loom\",\"optional\":true,\"req\":\"^0.5\",\"target\":\"cfg(loom)\"},{\"features\":[\"checkpoint\"],\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.5\",\"target\":\"cfg(loom)\"},{\"kind\":\"dev\",\"name\":\"memory-stats\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"slab\",\"req\":\"^0.4.2\"}],\"features\":{}}", "shellexpand_3.1.1": "{\"dependencies\":[{\"name\":\"bstr\",\"optional\":true,\"req\":\"^1.0.0-pre.2\"},{\"name\":\"dirs\",\"optional\":true,\"req\":\">=4, <7\"},{\"name\":\"os_str_bytes\",\"optional\":true,\"req\":\">=5, <7\"}],\"features\":{\"base-0\":[],\"default\":[\"base-0\",\"tilde\"],\"full\":[\"full-msrv-1-51\"],\"full-msrv-1-31\":[\"base-0\",\"tilde\"],\"full-msrv-1-51\":[\"full-msrv-1-31\",\"path\"],\"path\":[\"bstr\",\"os_str_bytes\"],\"tilde\":[\"dirs\"]}}", + "shlex_1.3.0": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "shlex_2.0.1": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "signal-hook-registry_1.4.8": "{\"dependencies\":[{\"name\":\"errno\",\"req\":\">=0.2, <0.4\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"signal-hook\",\"req\":\"~0.3\"}],\"features\":{}}", "signature_2.2.0": "{\"dependencies\":[{\"name\":\"derive\",\"optional\":true,\"package\":\"signature_derive\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"digest\",\"optional\":true,\"req\":\"^0.10.6\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6.4\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"}],\"features\":{\"alloc\":[],\"std\":[\"alloc\",\"rand_core?/std\"]}}", "simd-adler32_0.3.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"adler\",\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"adler32\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"const-generics\":[],\"default\":[\"std\",\"const-generics\"],\"nightly\":[],\"std\":[]}}", + "simd-adler32_0.3.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"adler\",\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"adler32\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"const-generics\":[],\"default\":[\"std\",\"const-generics\"],\"nightly\":[],\"std\":[]}}", "simd_cesu8_1.1.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"cesu8\",\"req\":\"^1.1.0\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"build\",\"name\":\"rustc_version\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"simdutf8\",\"req\":\"^0.1.4\"}],\"features\":{\"bench\":[],\"default\":[\"std\"],\"nightly\":[],\"std\":[\"simdutf8/std\"]}}", "simdutf8_0.1.5": "{\"dependencies\":[],\"features\":{\"aarch64_neon\":[],\"aarch64_neon_prefetch\":[],\"default\":[\"std\"],\"hints\":[],\"public_imp\":[],\"std\":[]}}", "simple_asn1_0.6.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"formatting\",\"macros\",\"parsing\"],\"name\":\"time\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"formatting\",\"macros\",\"parsing\",\"quickcheck\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\"}],\"features\":{}}", @@ -1268,6 +1181,7 @@ "strsim_0.11.1": "{\"dependencies\":[],\"features\":{}}", "subtle_2.6.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"const-generics\":[],\"core_hint_black_box\":[],\"default\":[\"std\",\"i128\"],\"i128\":[],\"nightly\":[],\"std\":[]}}", "syn_2.0.117": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.91\"},{\"default_features\":false,\"name\":\"quote\",\"optional\":true,\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1\"},{\"features\":[\"blocking\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.13\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"syn-test-suite\",\"req\":\"^0\"},{\"kind\":\"dev\",\"name\":\"tar\",\"req\":\"^0.4.16\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"termcolor\",\"req\":\"^1\"},{\"name\":\"unicode-ident\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\",\"target\":\"cfg(not(miri))\"}],\"features\":{\"clone-impls\":[],\"default\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"proc-macro\"],\"derive\":[],\"extra-traits\":[],\"fold\":[],\"full\":[],\"parsing\":[],\"printing\":[\"dep:quote\"],\"proc-macro\":[\"proc-macro2/proc-macro\",\"quote?/proc-macro\"],\"test\":[\"syn-test-suite/all-features\"],\"visit\":[],\"visit-mut\":[]}}", + "syn_3.0.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.91\"},{\"default_features\":false,\"name\":\"quote\",\"optional\":true,\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1\"},{\"features\":[\"blocking\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.13\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"syn-test-suite\",\"req\":\"^0\"},{\"kind\":\"dev\",\"name\":\"tar\",\"req\":\"^0.4.16\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"termcolor\",\"req\":\"^1\"},{\"name\":\"unicode-ident\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\",\"target\":\"cfg(not(miri))\"}],\"features\":{\"clone-impls\":[],\"default\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"proc-macro\"],\"derive\":[],\"extra-traits\":[],\"fold\":[],\"full\":[],\"parsing\":[],\"printing\":[\"dep:quote\"],\"proc-macro\":[\"proc-macro2/proc-macro\",\"quote?/proc-macro\"],\"test\":[\"syn-test-suite/all-features\"],\"visit\":[],\"visit-mut\":[]}}", "sync_wrapper_1.0.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"}],\"features\":{\"futures\":[\"futures-core\"]}}", "synstructure_0.13.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"visit\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"synstructure_test_traits\",\"req\":\"^0.1\"}],\"features\":{\"default\":[\"proc-macro\"],\"proc-macro\":[\"proc-macro2/proc-macro\",\"syn/proc-macro\",\"quote/proc-macro\"]}}", "system-configuration-sys_0.6.0": "{\"dependencies\":[{\"name\":\"core-foundation-sys\",\"req\":\"^0.8\"},{\"name\":\"libc\",\"req\":\"^0.2.149\"}],\"features\":{}}", @@ -1284,10 +1198,12 @@ "thiserror_1.0.69": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.73\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"name\":\"thiserror-impl\",\"req\":\"=1.0.69\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.81\"}],\"features\":{}}", "thiserror_2.0.18": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.73\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"name\":\"thiserror-impl\",\"req\":\"=2.0.18\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "thread_local_1.1.9": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"}],\"features\":{\"nightly\":[]}}", + "threadpool_1.8.1": "{\"dependencies\":[{\"name\":\"num_cpus\",\"req\":\"^1.13\"}],\"features\":{}}", "time-core_0.1.8": "{\"dependencies\":[],\"features\":{\"large-dates\":[]}}", "time-macros_0.2.27": "{\"dependencies\":[{\"name\":\"num-conv\",\"req\":\"^0.2.0\"},{\"name\":\"time-core\",\"req\":\"=0.1.8\"}],\"features\":{\"formatting\":[],\"large-dates\":[],\"parsing\":[],\"serde\":[]}}", "time_0.3.47": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.1\",\"target\":\"cfg(bench)\"},{\"features\":[\"powerfmt\"],\"name\":\"deranged\",\"req\":\"^0.5.2\"},{\"name\":\"itoa\",\"optional\":true,\"req\":\"^1.0.1\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.58\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.98\",\"target\":\"cfg(target_family = \\\"unix\\\")\"},{\"name\":\"num-conv\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"num-conv\",\"req\":\"^0.2.0\"},{\"name\":\"num_threads\",\"optional\":true,\"req\":\"^0.1.2\",\"target\":\"cfg(target_family = \\\"unix\\\")\"},{\"default_features\":false,\"name\":\"powerfmt\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"rand08\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rand08\",\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"name\":\"rand09\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.9.2\"},{\"default_features\":false,\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand09\",\"package\":\"rand\",\"req\":\"^0.9.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26.1\"},{\"kind\":\"dev\",\"name\":\"rstest_reuse\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.184\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.68\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.126\"},{\"name\":\"time-core\",\"req\":\"=0.1.8\"},{\"name\":\"time-macros\",\"optional\":true,\"req\":\"=0.2.27\"},{\"kind\":\"dev\",\"name\":\"time-macros\",\"req\":\"=0.2.27\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.102\",\"target\":\"cfg(__ui_tests)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\"],\"default\":[\"std\"],\"formatting\":[\"dep:itoa\",\"std\",\"time-macros?/formatting\"],\"large-dates\":[\"time-core/large-dates\",\"time-macros?/large-dates\"],\"local-offset\":[\"std\",\"dep:libc\",\"dep:num_threads\"],\"macros\":[\"dep:time-macros\"],\"parsing\":[\"time-macros?/parsing\"],\"quickcheck\":[\"dep:quickcheck\",\"alloc\",\"deranged/quickcheck\"],\"rand\":[\"rand08\",\"rand09\"],\"rand08\":[\"dep:rand08\",\"deranged/rand08\"],\"rand09\":[\"dep:rand09\",\"deranged/rand09\"],\"serde\":[\"dep:serde_core\",\"time-macros?/serde\",\"deranged/serde\"],\"serde-human-readable\":[\"serde\",\"formatting\",\"parsing\"],\"serde-well-known\":[\"serde\",\"formatting\",\"parsing\"],\"std\":[\"alloc\"],\"wasm-bindgen\":[\"dep:js-sys\"]}}", "tiny-keccak_2.0.2": "{\"dependencies\":[{\"name\":\"crunchy\",\"req\":\"^0.2.2\"}],\"features\":{\"cshake\":[],\"default\":[],\"fips202\":[\"keccak\",\"shake\",\"sha3\"],\"k12\":[],\"keccak\":[],\"kmac\":[\"cshake\"],\"parallel_hash\":[\"cshake\"],\"sha3\":[],\"shake\":[],\"sp800\":[\"cshake\",\"kmac\",\"tuple_hash\"],\"tuple_hash\":[\"cshake\"]}}", + "tiny_http_0.12.0": "{\"dependencies\":[{\"name\":\"ascii\",\"req\":\"^1.0\"},{\"name\":\"chunked_transfer\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"fdlimit\",\"req\":\"^0.1\"},{\"name\":\"httpdate\",\"req\":\"^1.0.2\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rustc-serialize\",\"req\":\"^0.3\"},{\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.20\"},{\"name\":\"rustls-pemfile\",\"optional\":true,\"req\":\"^0.2.1\"},{\"kind\":\"dev\",\"name\":\"sha1\",\"req\":\"^0.6.0\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"default\":[],\"ssl\":[\"ssl-openssl\"],\"ssl-openssl\":[\"openssl\",\"zeroize\"],\"ssl-rustls\":[\"rustls\",\"rustls-pemfile\",\"zeroize\"]}}", "tinystr_0.8.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2.3\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"name\":\"zerovec\",\"optional\":true,\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"zerovec?/alloc\"],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde_core\"],\"std\":[],\"zerovec\":[\"dep:zerovec\"]}}", "tinyvec_1.11.0": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"debugger_test\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"debugger_test_parser\",\"req\":\"^0.1\"},{\"name\":\"defmt\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"generic-array\",\"optional\":true,\"req\":\"^1.1.1\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"smallvec\",\"req\":\"^1\"},{\"name\":\"tinyvec_macros\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{\"alloc\":[\"tinyvec_macros\"],\"debugger_visualizer\":[],\"default\":[],\"experimental_write_impl\":[],\"grab_spare_slice\":[],\"latest_stable_rust\":[\"rustc_1_61\"],\"nightly_slice_partition_dedup\":[],\"real_blackbox\":[\"criterion/real_blackbox\"],\"rustc_1_40\":[],\"rustc_1_55\":[],\"rustc_1_57\":[],\"rustc_1_61\":[\"rustc_1_57\"],\"serde\":[\"dep:serde_core\"],\"std\":[\"alloc\"]}}", "tinyvec_macros_0.1.1": "{\"dependencies\":[],\"features\":{}}", @@ -1301,11 +1217,14 @@ "tokio-util_0.7.18": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3.0\"},{\"name\":\"bytes\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.0\"},{\"name\":\"futures-core\",\"req\":\"^0.3.0\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"futures-sink\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"futures-test\",\"req\":\"^0.3.5\"},{\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.0\"},{\"default_features\":false,\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15.0\"},{\"features\":[\"futures\",\"checkpoint\"],\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"^0.12.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.4\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"req\":\"^1.44.0\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.29\"}],\"features\":{\"__docs_rs\":[\"futures-util\"],\"codec\":[],\"compat\":[\"futures-io\"],\"default\":[],\"full\":[\"codec\",\"compat\",\"io-util\",\"time\",\"net\",\"rt\",\"join-map\"],\"io\":[],\"io-util\":[\"io\",\"tokio/rt\",\"tokio/io-util\"],\"join-map\":[\"rt\",\"hashbrown\"],\"net\":[\"tokio/net\"],\"rt\":[\"tokio/rt\",\"tokio/sync\",\"futures-util\"],\"time\":[\"tokio/time\",\"slab\"]}}", "tokio_1.50.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3\"},{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.58\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.2.1\"},{\"features\":[\"async-await\"],\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"futures-concurrency\",\"req\":\"^7.6.3\"},{\"kind\":\"dev\",\"name\":\"futures-test\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"io-uring\",\"optional\":true,\"req\":\"^0.7.11\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.168\",\"target\":\"cfg(unix)\"},{\"features\":[\"futures\",\"checkpoint\"],\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"name\":\"mio\",\"optional\":true,\"req\":\"^1.0.1\"},{\"default_features\":false,\"features\":[\"os-poll\",\"os-ext\"],\"name\":\"mio\",\"optional\":true,\"req\":\"^1.0.1\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"features\":[\"tokio\"],\"kind\":\"dev\",\"name\":\"mio-aio\",\"req\":\"^1\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"kind\":\"dev\",\"name\":\"mockall\",\"req\":\"^0.13.0\"},{\"default_features\":false,\"features\":[\"aio\",\"fs\",\"socket\"],\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.29.0\",\"target\":\"cfg(unix)\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"signal-hook-registry\",\"optional\":true,\"req\":\"^1.1.1\",\"target\":\"cfg(unix)\"},{\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.9\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"socket2\",\"req\":\"^0.6.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"name\":\"tokio-macros\",\"optional\":true,\"req\":\"~2.6.0\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.0\"},{\"features\":[\"rt\"],\"kind\":\"dev\",\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.29\",\"target\":\"cfg(tokio_unstable)\"},{\"kind\":\"dev\",\"name\":\"tracing-mock\",\"req\":\"=0.1.0-beta.1\",\"target\":\"cfg(all(tokio_unstable, target_has_atomic = \\\"64\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.0\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"windows-sys\",\"optional\":true,\"req\":\"^0.61\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_Foundation\",\"Win32_Security_Authorization\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[],\"fs\":[],\"full\":[\"fs\",\"io-util\",\"io-std\",\"macros\",\"net\",\"parking_lot\",\"process\",\"rt\",\"rt-multi-thread\",\"signal\",\"sync\",\"time\"],\"io-std\":[],\"io-uring\":[\"dep:io-uring\",\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"dep:slab\"],\"io-util\":[\"bytes\"],\"macros\":[\"tokio-macros\"],\"net\":[\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"mio/net\",\"socket2\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_Security\",\"windows-sys/Win32_Storage_FileSystem\",\"windows-sys/Win32_System_Pipes\",\"windows-sys/Win32_System_SystemServices\"],\"process\":[\"bytes\",\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"mio/net\",\"signal-hook-registry\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_System_Threading\",\"windows-sys/Win32_System_WindowsProgramming\"],\"rt\":[],\"rt-multi-thread\":[\"rt\"],\"signal\":[\"libc\",\"mio/os-poll\",\"mio/net\",\"mio/os-ext\",\"signal-hook-registry\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_System_Console\"],\"sync\":[],\"taskdump\":[\"dep:backtrace\"],\"test-util\":[\"rt\",\"sync\",\"time\"],\"time\":[]}}", "tokio_1.52.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3\"},{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.58\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"kind\":\"dev\",\"name\":\"backtrace\",\"req\":\"^0.3.58\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.2.1\"},{\"features\":[\"async-await\"],\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"futures-concurrency\",\"req\":\"^7.6.3\"},{\"kind\":\"dev\",\"name\":\"futures-test\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"io-uring\",\"optional\":true,\"req\":\"^0.7.11\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.168\",\"target\":\"cfg(unix)\"},{\"features\":[\"futures\",\"checkpoint\"],\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"name\":\"mio\",\"optional\":true,\"req\":\"^1.2.0\"},{\"default_features\":false,\"features\":[\"os-poll\",\"os-ext\"],\"name\":\"mio\",\"optional\":true,\"req\":\"^1.2.0\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"features\":[\"tokio\"],\"kind\":\"dev\",\"name\":\"mio-aio\",\"req\":\"^2\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"kind\":\"dev\",\"name\":\"mockall\",\"req\":\"^0.13.0\"},{\"default_features\":false,\"features\":[\"aio\",\"fs\",\"socket\"],\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.31.0\",\"target\":\"cfg(unix)\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"signal-hook-registry\",\"optional\":true,\"req\":\"^1.1.1\",\"target\":\"cfg(unix)\"},{\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.9\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6.3\",\"target\":\"cfg(any(not(target_family = \\\"wasm\\\"), all(target_os = \\\"wasi\\\", not(target_env = \\\"p1\\\"))))\"},{\"kind\":\"dev\",\"name\":\"socket2\",\"req\":\"^0.6.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"name\":\"tokio-macros\",\"optional\":true,\"req\":\"~2.7.0\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.0\"},{\"features\":[\"rt\"],\"kind\":\"dev\",\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.29\",\"target\":\"cfg(tokio_unstable)\"},{\"kind\":\"dev\",\"name\":\"tracing-mock\",\"req\":\"=0.1.0-beta.1\",\"target\":\"cfg(all(tokio_unstable, target_has_atomic = \\\"64\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.0\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"windows-sys\",\"optional\":true,\"req\":\"^0.61\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_Foundation\",\"Win32_Security_Authorization\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[],\"fs\":[],\"full\":[\"fs\",\"io-util\",\"io-std\",\"macros\",\"net\",\"parking_lot\",\"process\",\"rt\",\"rt-multi-thread\",\"signal\",\"sync\",\"time\"],\"io-std\":[],\"io-uring\":[\"dep:io-uring\",\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"dep:slab\"],\"io-util\":[\"bytes\"],\"macros\":[\"tokio-macros\"],\"net\":[\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"mio/net\",\"socket2\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_Security\",\"windows-sys/Win32_Storage_FileSystem\",\"windows-sys/Win32_System_Pipes\",\"windows-sys/Win32_System_SystemServices\"],\"process\":[\"bytes\",\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"mio/net\",\"signal-hook-registry\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_System_Threading\",\"windows-sys/Win32_System_WindowsProgramming\"],\"rt\":[],\"rt-multi-thread\":[\"rt\"],\"signal\":[\"libc\",\"mio/os-poll\",\"mio/net\",\"mio/os-ext\",\"signal-hook-registry\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_System_Console\"],\"sync\":[],\"taskdump\":[\"dep:backtrace\"],\"test-util\":[\"rt\",\"sync\",\"time\"],\"time\":[]}}", - "tonic-build_0.13.1": "{\"dependencies\":[{\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"prost-build\",\"optional\":true,\"req\":\"^0.13\"},{\"name\":\"prost-types\",\"optional\":true,\"req\":\"^0.13\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{\"cleanup-markdown\":[\"prost-build?/cleanup-markdown\"],\"default\":[\"transport\",\"prost\"],\"prost\":[\"prost-build\",\"dep:prost-types\"],\"transport\":[]}}", "tonic-build_0.14.5": "{\"dependencies\":[{\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{\"default\":[\"transport\"],\"transport\":[]}}", + "tonic-build_0.14.6": "{\"dependencies\":[{\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{\"default\":[\"transport\"],\"transport\":[]}}", + "tonic-prost-build_0.14.6": "{\"dependencies\":[{\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"prost-build\",\"req\":\"^0.14\"},{\"name\":\"prost-types\",\"req\":\"^0.14\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"},{\"name\":\"tempfile\",\"req\":\"^3.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"tonic\",\"req\":\"^0.14.6\"},{\"default_features\":false,\"name\":\"tonic-build\",\"req\":\"^0.14.6\"}],\"features\":{\"cleanup-markdown\":[\"prost-build/cleanup-markdown\"],\"default\":[\"transport\",\"cleanup-markdown\"],\"transport\":[\"tonic-build/transport\"]}}", "tonic-prost_0.14.5": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"http-body\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"name\":\"prost\",\"req\":\"^0.14\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"tonic\",\"req\":\"^0.14.0\"}],\"features\":{}}", - "tonic_0.13.1": "{\"dependencies\":[{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.13\"},{\"default_features\":false,\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"http\",\"req\":\"^1\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"features\":[\"http1\",\"http2\"],\"name\":\"hyper\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"hyper-timeout\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"tokio\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.4\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project\",\"req\":\"^1.0.11\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"prost\",\"optional\":true,\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"logging\",\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26.1\"},{\"default_features\":false,\"name\":\"tokio-stream\",\"req\":\"^0.1.16\"},{\"default_features\":false,\"name\":\"tower\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5\"},{\"name\":\"tower-layer\",\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^0.26\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13.0\"}],\"features\":{\"_tls-any\":[\"dep:tokio-rustls\",\"dep:tokio\",\"tokio?/rt\",\"tokio?/macros\"],\"channel\":[\"dep:hyper\",\"hyper?/client\",\"dep:hyper-util\",\"hyper-util?/client-legacy\",\"dep:tower\",\"tower?/balance\",\"tower?/buffer\",\"tower?/discover\",\"tower?/limit\",\"tower?/util\",\"dep:tokio\",\"tokio?/time\",\"dep:hyper-timeout\"],\"codegen\":[\"dep:async-trait\"],\"default\":[\"router\",\"transport\",\"codegen\",\"prost\"],\"deflate\":[\"dep:flate2\"],\"gzip\":[\"dep:flate2\"],\"prost\":[\"dep:prost\"],\"router\":[\"dep:axum\",\"dep:tower\",\"tower?/util\"],\"server\":[\"dep:h2\",\"dep:hyper\",\"hyper?/server\",\"dep:hyper-util\",\"hyper-util?/service\",\"hyper-util?/server-auto\",\"dep:socket2\",\"dep:tokio\",\"tokio?/macros\",\"tokio?/net\",\"tokio?/time\",\"tokio-stream/net\",\"dep:tower\",\"tower?/util\",\"tower?/limit\"],\"tls-aws-lc\":[\"_tls-any\",\"tokio-rustls/aws-lc-rs\"],\"tls-native-roots\":[\"_tls-any\",\"channel\",\"dep:rustls-native-certs\"],\"tls-ring\":[\"_tls-any\",\"tokio-rustls/ring\"],\"tls-webpki-roots\":[\"_tls-any\",\"channel\",\"dep:webpki-roots\"],\"transport\":[\"server\",\"channel\"],\"zstd\":[\"dep:zstd\"]}}", + "tonic-prost_0.14.6": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"http-body\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"name\":\"prost\",\"req\":\"^0.14\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"tonic\",\"req\":\"^0.14.6\"}],\"features\":{}}", + "tonic-types_0.14.6": "{\"dependencies\":[{\"name\":\"prost\",\"req\":\"^0.14\"},{\"name\":\"prost-types\",\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"tonic\",\"req\":\"^0.14.6\"}],\"features\":{}}", "tonic_0.14.5": "{\"dependencies\":[{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.13\"},{\"default_features\":false,\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"http\",\"req\":\"^1.1.0\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"features\":[\"http1\",\"http2\"],\"name\":\"hyper\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"hyper-timeout\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"tokio\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.11\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project\",\"req\":\"^1.0.11\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.0\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.2\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"logging\",\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26.1\"},{\"default_features\":false,\"name\":\"tokio-stream\",\"req\":\"^0.1.16\"},{\"default_features\":false,\"name\":\"tower\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"load-shed\",\"timeout\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5\"},{\"name\":\"tower-layer\",\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13.0\"}],\"features\":{\"_tls-any\":[\"dep:tokio\",\"tokio?/rt\",\"tokio?/macros\",\"tls-connect-info\"],\"channel\":[\"dep:hyper\",\"hyper?/client\",\"dep:hyper-util\",\"hyper-util?/client-legacy\",\"dep:tower\",\"tower?/balance\",\"tower?/buffer\",\"tower?/discover\",\"tower?/limit\",\"tower?/load-shed\",\"tower?/util\",\"dep:tokio\",\"tokio?/time\",\"dep:hyper-timeout\"],\"codegen\":[\"dep:async-trait\"],\"default\":[\"router\",\"transport\",\"codegen\"],\"deflate\":[\"dep:flate2\"],\"gzip\":[\"dep:flate2\"],\"router\":[\"dep:axum\",\"dep:tower\",\"tower?/util\"],\"server\":[\"dep:h2\",\"dep:hyper\",\"hyper?/server\",\"dep:hyper-util\",\"hyper-util?/service\",\"hyper-util?/server-auto\",\"dep:socket2\",\"dep:tokio\",\"tokio?/macros\",\"tokio?/net\",\"tokio?/time\",\"tokio-stream/net\",\"dep:tower\",\"tower?/util\",\"tower?/limit\",\"tower?/load-shed\"],\"tls-aws-lc\":[\"_tls-any\",\"tokio-rustls/aws-lc-rs\"],\"tls-connect-info\":[\"dep:tokio-rustls\"],\"tls-native-roots\":[\"_tls-any\",\"channel\",\"dep:rustls-native-certs\"],\"tls-ring\":[\"_tls-any\",\"tokio-rustls/ring\"],\"tls-webpki-roots\":[\"_tls-any\",\"channel\",\"dep:webpki-roots\"],\"transport\":[\"server\",\"channel\"],\"zstd\":[\"dep:zstd\"]}}", + "tonic_0.14.6": "{\"dependencies\":[{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.13\"},{\"default_features\":false,\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"http\",\"req\":\"^1.1.0\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"features\":[\"http1\",\"http2\"],\"name\":\"hyper\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"hyper-timeout\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"tokio\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.11\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project\",\"req\":\"^1.0.11\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.0\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.2\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"logging\",\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26.1\"},{\"default_features\":false,\"name\":\"tokio-stream\",\"req\":\"^0.1.16\"},{\"default_features\":false,\"name\":\"tower\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"load-shed\",\"timeout\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5\"},{\"name\":\"tower-layer\",\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13.0\"}],\"features\":{\"_tls-any\":[\"dep:tokio\",\"tokio?/rt\",\"tokio?/macros\",\"tls-connect-info\"],\"channel\":[\"dep:hyper\",\"hyper?/client\",\"dep:hyper-util\",\"hyper-util?/client-legacy\",\"dep:tower\",\"tower?/balance\",\"tower?/buffer\",\"tower?/discover\",\"tower?/limit\",\"tower?/load-shed\",\"tower?/util\",\"dep:tokio\",\"tokio?/time\",\"dep:hyper-timeout\"],\"codegen\":[\"dep:async-trait\"],\"default\":[\"router\",\"transport\",\"codegen\"],\"deflate\":[\"dep:flate2\"],\"gzip\":[\"dep:flate2\"],\"router\":[\"dep:axum\",\"dep:tower\",\"tower?/util\"],\"server\":[\"dep:h2\",\"dep:hyper\",\"hyper?/server\",\"dep:hyper-util\",\"hyper-util?/service\",\"hyper-util?/server-auto\",\"dep:socket2\",\"dep:tokio\",\"tokio?/macros\",\"tokio?/net\",\"tokio?/time\",\"tokio-stream/net\",\"dep:tower\",\"tower?/util\",\"tower?/limit\",\"tower?/load-shed\"],\"tls-aws-lc\":[\"_tls-any\",\"tokio-rustls/aws-lc-rs\"],\"tls-connect-info\":[\"dep:tokio-rustls\"],\"tls-native-roots\":[\"_tls-any\",\"channel\",\"dep:rustls-native-certs\"],\"tls-ring\":[\"_tls-any\",\"tokio-rustls/ring\"],\"tls-webpki-roots\":[\"_tls-any\",\"channel\",\"dep:webpki-roots\"],\"transport\":[\"server\",\"channel\"],\"zstd\":[\"dep:zstd\"]}}", "tower-http_0.6.11": "{\"dependencies\":[{\"features\":[\"tokio\"],\"name\":\"async-compression\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"bitflags\",\"req\":\"^2.0.2\"},{\"kind\":\"dev\",\"name\":\"brotli\",\"req\":\"^8\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.14\"},{\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.14\"},{\"name\":\"http\",\"req\":\"^1.0\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"http-range-header\",\"optional\":true,\"req\":\"^0.4.0\"},{\"name\":\"httpdate\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1\"},{\"features\":[\"client-legacy\",\"http1\",\"server\",\"service\",\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"mime\",\"optional\":true,\"req\":\"^0.3.17\"},{\"default_features\":false,\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.1.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"sync_wrapper\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.6\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"io\"],\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"tower\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"buffer\",\"util\",\"retry\",\"make\",\"timeout\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.5\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"zstd\",\"req\":\"^0.13\"}],\"features\":{\"add-extension\":[],\"async-compression\":[],\"auth\":[\"base64\",\"validate-request\"],\"catch-panic\":[\"tracing\",\"futures-util/std\",\"dep:http-body\",\"dep:http-body-util\"],\"compression-br\":[\"dep:async-compression\",\"async-compression?/brotli\",\"futures-core\",\"dep:http-body\",\"tokio-util\",\"dep:tokio\"],\"compression-deflate\":[\"dep:async-compression\",\"async-compression?/zlib\",\"futures-core\",\"dep:http-body\",\"tokio-util\",\"dep:tokio\"],\"compression-full\":[\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"compression-zstd\"],\"compression-gzip\":[\"dep:async-compression\",\"async-compression?/gzip\",\"futures-core\",\"dep:http-body\",\"tokio-util\",\"dep:tokio\"],\"compression-zstd\":[\"dep:async-compression\",\"async-compression?/zstd\",\"futures-core\",\"dep:http-body\",\"tokio-util\",\"dep:tokio\"],\"cors\":[],\"decompression-br\":[\"dep:async-compression\",\"async-compression?/brotli\",\"futures-core\",\"dep:http-body\",\"dep:http-body-util\",\"tokio-util\",\"dep:tokio\"],\"decompression-deflate\":[\"dep:async-compression\",\"async-compression?/zlib\",\"futures-core\",\"dep:http-body\",\"dep:http-body-util\",\"tokio-util\",\"dep:tokio\"],\"decompression-full\":[\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"decompression-zstd\"],\"decompression-gzip\":[\"dep:async-compression\",\"async-compression?/gzip\",\"futures-core\",\"dep:http-body\",\"dep:http-body-util\",\"tokio-util\",\"dep:tokio\"],\"decompression-zstd\":[\"dep:async-compression\",\"async-compression?/zstd\",\"futures-core\",\"dep:http-body\",\"dep:http-body-util\",\"tokio-util\",\"dep:tokio\"],\"default\":[],\"follow-redirect\":[\"futures-util\",\"dep:http-body\",\"dep:url\",\"tower/util\"],\"fs\":[\"dep:tokio\",\"tokio?/fs\",\"tokio?/io-util\",\"futures-core\",\"futures-util\",\"dep:http-body\",\"dep:http-body-util\",\"tokio-util/io\",\"dep:http-range-header\",\"mime_guess\",\"mime\",\"percent-encoding\",\"httpdate\",\"set-status\",\"futures-util/alloc\"],\"full\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-full\",\"cors\",\"decompression-full\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"on-early-drop\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"limit\":[\"dep:http-body\",\"dep:http-body-util\"],\"map-request-body\":[],\"map-response-body\":[],\"metrics\":[\"dep:http-body\",\"dep:tokio\",\"tokio?/time\"],\"normalize-path\":[],\"on-early-drop\":[\"dep:http-body\"],\"propagate-header\":[],\"redirect\":[],\"request-id\":[\"uuid\"],\"sensitive-headers\":[],\"set-header\":[],\"set-status\":[],\"timeout\":[\"dep:http-body\",\"dep:tokio\",\"tokio?/time\"],\"tokio\":[],\"trace\":[\"dep:http-body\",\"tracing\"],\"util\":[\"tower\"],\"validate-request\":[\"mime\"]}}", "tower-layer_0.3.3": "{\"dependencies\":[],\"features\":{}}", "tower-service_0.3.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.22\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^0.2\"},{\"features\":[\"macros\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.6.2\"},{\"kind\":\"dev\",\"name\":\"tower-layer\",\"req\":\"^0.3\"}],\"features\":{}}", @@ -1314,25 +1233,31 @@ "tracing-attributes_0.1.31": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1.67\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1.0.20\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.9\"},{\"default_features\":false,\"features\":[\"full\",\"parsing\",\"printing\",\"visit-mut\",\"clone-impls\",\"extra-traits\",\"proc-macro\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.2\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"features\":[\"env-filter\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.64\"}],\"features\":{\"async-await\":[]}}", "tracing-core_0.1.36": "{\"dependencies\":[{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.13.0\"},{\"default_features\":false,\"name\":\"valuable\",\"optional\":true,\"req\":\"^0.1.0\",\"target\":\"cfg(tracing_unstable)\"}],\"features\":{\"default\":[\"std\",\"valuable?/std\"],\"std\":[\"once_cell\"]}}", "tracing-log_0.2.0": "{\"dependencies\":[{\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.7.6\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"name\":\"log\",\"req\":\"^0.4.17\"},{\"name\":\"lru\",\"optional\":true,\"req\":\"^0.7.7\"},{\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"name\":\"tracing-core\",\"req\":\"^0.1.28\"}],\"features\":{\"default\":[\"log-tracer\",\"std\"],\"interest-cache\":[\"lru\",\"ahash\"],\"log-tracer\":[],\"std\":[\"log/std\"]}}", - "tracing-opentelemetry_0.31.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.56\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1.56\"},{\"default_features\":false,\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.17\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.17\"},{\"name\":\"js-sys\",\"req\":\"^0.3.64\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"lazy_static\",\"optional\":true,\"req\":\"^1.0.2\"},{\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"default_features\":false,\"features\":[\"trace\"],\"name\":\"opentelemetry\",\"req\":\"^0.30.0\"},{\"features\":[\"trace\",\"metrics\"],\"kind\":\"dev\",\"name\":\"opentelemetry\",\"req\":\"^0.30.0\"},{\"features\":[\"metrics\",\"grpc-tonic\"],\"kind\":\"dev\",\"name\":\"opentelemetry-otlp\",\"req\":\"^0.30.0\"},{\"features\":[\"semconv_experimental\"],\"kind\":\"dev\",\"name\":\"opentelemetry-semantic-conventions\",\"req\":\"^0.30.0\"},{\"features\":[\"trace\",\"metrics\"],\"kind\":\"dev\",\"name\":\"opentelemetry-stdout\",\"req\":\"^0.30.0\"},{\"default_features\":false,\"features\":[\"trace\"],\"name\":\"opentelemetry_sdk\",\"req\":\"^0.30.0\"},{\"default_features\":false,\"features\":[\"trace\",\"rt-tokio\",\"experimental_metrics_custom_reader\"],\"kind\":\"dev\",\"name\":\"opentelemetry_sdk\",\"req\":\"^0.30.0\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.14.0\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"thiserror-1\",\"optional\":true,\"package\":\"thiserror\",\"req\":\"^1.0.31\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"default_features\":false,\"features\":[\"std\",\"attributes\"],\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"name\":\"tracing-core\",\"req\":\"^0.1.28\"},{\"kind\":\"dev\",\"name\":\"tracing-error\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"tracing-log\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"registry\",\"std\"],\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"default_features\":false,\"features\":[\"registry\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"name\":\"web-time\",\"req\":\"^1.0.0\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"}],\"features\":{\"default\":[\"tracing-log\",\"metrics\"],\"metrics\":[\"opentelemetry/metrics\",\"opentelemetry_sdk/metrics\",\"smallvec\"],\"metrics_gauge_unstable\":[]}}", + "tracing-opentelemetry_0.33.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"name\":\"js-sys\",\"req\":\"^0.3.64\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"lazy_static\",\"optional\":true,\"req\":\"^1.0.2\"},{\"default_features\":false,\"features\":[\"trace\"],\"name\":\"opentelemetry\",\"req\":\"^0.32.0\"},{\"features\":[\"trace\",\"metrics\"],\"kind\":\"dev\",\"name\":\"opentelemetry\",\"req\":\"^0.32.0\"},{\"features\":[\"metrics\",\"grpc-tonic\"],\"kind\":\"dev\",\"name\":\"opentelemetry-otlp\",\"req\":\"^0.32.0\"},{\"features\":[\"semconv_experimental\"],\"kind\":\"dev\",\"name\":\"opentelemetry-semantic-conventions\",\"req\":\"^0.32.0\"},{\"features\":[\"trace\",\"metrics\"],\"kind\":\"dev\",\"name\":\"opentelemetry-stdout\",\"req\":\"^0.32.0\"},{\"default_features\":false,\"features\":[\"trace\",\"experimental_metrics_custom_reader\",\"testing\"],\"kind\":\"dev\",\"name\":\"opentelemetry_sdk\",\"req\":\"^0.32.0\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.15.0\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"default_features\":false,\"features\":[\"std\",\"attributes\"],\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"name\":\"tracing-core\",\"req\":\"^0.1.28\"},{\"kind\":\"dev\",\"name\":\"tracing-error\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"tracing-log\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"registry\",\"std\"],\"name\":\"tracing-subscriber\",\"req\":\"^0.3.22\"},{\"default_features\":false,\"features\":[\"registry\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"name\":\"web-time\",\"req\":\"^1.0.0\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"}],\"features\":{\"default\":[\"tracing-log\",\"metrics\"],\"metrics\":[\"opentelemetry/metrics\",\"smallvec\"]}}", "tracing-serde_0.2.0": "{\"dependencies\":[{\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"tracing-core\",\"req\":\"^0.1.28\"},{\"default_features\":false,\"name\":\"valuable-serde\",\"optional\":true,\"req\":\"^0.1.0\",\"target\":\"cfg(tracing_unstable)\"},{\"default_features\":false,\"name\":\"valuable_crate\",\"optional\":true,\"package\":\"valuable\",\"req\":\"^0.1.0\",\"target\":\"cfg(tracing_unstable)\"}],\"features\":{\"valuable\":[\"valuable_crate\",\"valuable-serde\",\"tracing-core/valuable\"]}}", "tracing-subscriber_0.3.23": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"clock\",\"std\"],\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.26\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"name\":\"matchers\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"nu-ansi-term\",\"optional\":true,\"req\":\"^0.50.0\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.13.0\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.1\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"regex-automata\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.140\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.82\"},{\"name\":\"sharded-slab\",\"optional\":true,\"req\":\"^0.1.4\"},{\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.9.0\"},{\"name\":\"thread_local\",\"optional\":true,\"req\":\"^1.1.4\"},{\"features\":[\"formatting\"],\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.2\"},{\"features\":[\"formatting\",\"macros\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.2\"},{\"features\":[\"rt\",\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.43\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.43\"},{\"default_features\":false,\"name\":\"tracing-core\",\"req\":\"^0.1.35\"},{\"default_features\":false,\"features\":[\"std-future\",\"std\"],\"kind\":\"dev\",\"name\":\"tracing-futures\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"log-tracer\",\"std\"],\"name\":\"tracing-log\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"tracing-log\",\"req\":\"^0.2.0\"},{\"name\":\"tracing-serde\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"valuable-serde\",\"optional\":true,\"req\":\"^0.1.0\",\"target\":\"cfg(tracing_unstable)\"},{\"default_features\":false,\"name\":\"valuable_crate\",\"optional\":true,\"package\":\"valuable\",\"req\":\"^0.1.0\",\"target\":\"cfg(tracing_unstable)\"}],\"features\":{\"alloc\":[],\"ansi\":[\"fmt\",\"nu-ansi-term\"],\"default\":[\"smallvec\",\"fmt\",\"ansi\",\"tracing-log\",\"std\"],\"env-filter\":[\"matchers\",\"once_cell\",\"tracing\",\"std\",\"thread_local\",\"dep:regex-automata\"],\"fmt\":[\"registry\",\"std\"],\"json\":[\"tracing-serde\",\"serde\",\"serde_json\"],\"local-time\":[\"time/local-offset\"],\"nu-ansi-term\":[\"dep:nu-ansi-term\"],\"regex\":[],\"registry\":[\"sharded-slab\",\"thread_local\",\"std\"],\"std\":[\"alloc\",\"tracing-core/std\"],\"valuable\":[\"tracing-core/valuable\",\"valuable_crate\",\"valuable-serde\",\"tracing-serde/valuable\"]}}", "tracing-test-macro_0.2.5": "{\"dependencies\":[{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"no-env-filter\":[]}}", "tracing-test_0.2.5": "{\"dependencies\":[{\"features\":[\"rt-multi-thread\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"name\":\"tracing-core\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\"],\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"tracing-test-macro\",\"req\":\"^0.2.5\"}],\"features\":{\"no-env-filter\":[\"tracing-test-macro/no-env-filter\"]}}", "tracing_0.1.44": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.21\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.9\"},{\"name\":\"tracing-attributes\",\"optional\":true,\"req\":\"^0.1.31\"},{\"default_features\":false,\"name\":\"tracing-core\",\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.38\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"}],\"features\":{\"async-await\":[],\"attributes\":[\"tracing-attributes\"],\"default\":[\"std\",\"attributes\"],\"log-always\":[\"log\"],\"max_level_debug\":[],\"max_level_error\":[],\"max_level_info\":[],\"max_level_off\":[],\"max_level_trace\":[],\"max_level_warn\":[],\"release_max_level_debug\":[],\"release_max_level_error\":[],\"release_max_level_info\":[],\"release_max_level_off\":[],\"release_max_level_trace\":[],\"release_max_level_warn\":[],\"std\":[\"tracing-core/std\"],\"valuable\":[\"tracing-core/valuable\"]}}", "try-lock_0.2.5": "{\"dependencies\":[],\"features\":{}}", + "twoway_0.1.8": "{\"dependencies\":[{\"name\":\"galil-seiferas\",\"optional\":true,\"req\":\"^0.1.1\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.7.0\"},{\"features\":[\"unstable\"],\"name\":\"jetscii\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"macro-attr\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"newtype_derive\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"odds\",\"req\":\"^0.2.26\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.3.10\"},{\"name\":\"unchecked-index\",\"optional\":true,\"req\":\"^0.2.2\"}],\"features\":{\"all\":[\"jetscii\",\"pcmp\",\"pattern\",\"test-set\"],\"benchmarks\":[\"galil-seiferas\",\"pattern\",\"unchecked-index\"],\"default\":[\"use_std\"],\"pattern\":[],\"pcmp\":[\"unchecked-index\"],\"test-set\":[],\"use_std\":[\"memchr/use_std\"]}}", "typed-builder-macro_0.20.1": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", "typed-builder_0.20.1": "{\"dependencies\":[{\"name\":\"typed-builder-macro\",\"req\":\"=0.20.1\"}],\"features\":{}}", "typed-path_0.12.3": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "typenum_1.19.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"scale-info\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"const-generics\":[],\"force_unix_path_separator\":[],\"i128\":[],\"no_std\":[],\"scale_info\":[\"scale-info/derive\"],\"strict\":[]}}", + "typespec_1.1.0": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1.11.1\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"features\":[\"serialize\",\"serde-types\"],\"name\":\"quick-xml\",\"optional\":true,\"req\":\"^0.41.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.149\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"name\":\"url\",\"req\":\"^2.5\"}],\"features\":{\"default\":[\"http\",\"json\"],\"http\":[],\"json\":[\"dep:serde\",\"dep:serde_json\"],\"xml\":[\"dep:serde\",\"dep:quick-xml\"]}}", + "typespec_client_core_1.0.0": "{\"dependencies\":[{\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1.11.1\"},{\"name\":\"dyn-clone\",\"req\":\"^1.0\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"gloo-timers\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"pin-project\",\"req\":\"^1.1\"},{\"features\":[\"sys_rng\"],\"name\":\"rand\",\"req\":\"^0.10.1\"},{\"default_features\":false,\"features\":[\"stream\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.13.2\"},{\"name\":\"rust_decimal\",\"optional\":true,\"req\":\"^1.40.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.149\"},{\"features\":[\"serde-well-known\",\"macros\"],\"name\":\"time\",\"req\":\"^0.3.47\"},{\"default_features\":false,\"features\":[\"macros\",\"time\",\"macros\",\"rt-multi-thread\",\"time\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.49\"},{\"default_features\":false,\"features\":[\"macros\",\"time\",\"fs\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.49\"},{\"name\":\"tracing\",\"req\":\"^0.1.44\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.44\"},{\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"typespec\",\"req\":\"^1.0.0\"},{\"name\":\"typespec_macros\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"typespec_macros\",\"req\":\"^1.0.0\"},{\"name\":\"url\",\"req\":\"^2.5\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"req\":\"^1.20\"}],\"features\":{\"debug\":[\"typespec_macros?/debug\"],\"decimal\":[\"dep:rust_decimal\"],\"default\":[\"http\",\"json\",\"reqwest\",\"reqwest_deflate\",\"reqwest_gzip\",\"reqwest_rustls\",\"tokio\"],\"derive\":[\"dep:typespec_macros\"],\"http\":[\"typespec/http\"],\"json\":[\"dep:serde_json\",\"typespec/json\"],\"reqwest\":[\"dep:reqwest\"],\"reqwest_deflate\":[\"reqwest\",\"reqwest/deflate\"],\"reqwest_gzip\":[\"reqwest\",\"reqwest/gzip\"],\"reqwest_rustls\":[\"reqwest\",\"reqwest/rustls\"],\"test\":[],\"tokio\":[\"tokio/sync\",\"tokio/time\"],\"xml\":[\"dep:serde_json\",\"typespec/xml\"]}}", + "typespec_macros_1.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"cargo_metadata\",\"req\":\"^0.23.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"name\":\"rustc_version\",\"req\":\"^0.4\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.149\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.115\"},{\"default_features\":false,\"features\":[\"macros\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.49\"}],\"features\":{\"debug\":[]}}", "ucd-trie_0.1.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "unicase_2.8.1": "{\"dependencies\":[],\"features\":{\"nightly\":[]}}", + "unicase_2.9.0": "{\"dependencies\":[],\"features\":{\"nightly\":[]}}", "unicode-bidi_0.3.18": "{\"dependencies\":[{\"name\":\"flame\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"flamer\",\"optional\":true,\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\">=0.8, <2.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\">=0.8, <2.0\"},{\"features\":[\"union\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\">=1.13\"}],\"features\":{\"bench_it\":[],\"default\":[\"std\",\"hardcoded-data\"],\"flame_it\":[\"flame\",\"flamer\"],\"hardcoded-data\":[],\"std\":[],\"unstable\":[],\"with_serde\":[\"serde\"]}}", "unicode-ident_1.0.24": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"fst\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"roaring\",\"req\":\"^0.11\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"ucd-trie\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"unicode-xid\",\"req\":\"^0.2.6\"}],\"features\":{}}", "unicode-normalization_0.1.24": "{\"dependencies\":[{\"features\":[\"alloc\"],\"name\":\"tinyvec\",\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "unicode-properties_0.1.3": "{\"dependencies\":[],\"features\":{\"default\":[\"general-category\",\"emoji\"],\"emoji\":[],\"general-category\":[]}}", "unicode-xid_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"}],\"features\":{\"bench\":[],\"default\":[],\"no_std\":[]}}", "untrusted_0.9.0": "{\"dependencies\":[],\"features\":{}}", + "ureq_2.12.1": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"brotli-decompressor\",\"optional\":true,\"req\":\"^4.0.0\"},{\"default_features\":false,\"name\":\"cookie\",\"optional\":true,\"req\":\"^0.18\"},{\"default_features\":false,\"features\":[\"preserve_order\",\"serde_json\"],\"name\":\"cookie_store\",\"optional\":true,\"req\":\"^0.21.1\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"humantime\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"<=0.9\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0.22\"},{\"name\":\"hootbin\",\"optional\":true,\"req\":\"^0.1.5\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"name\":\"http-02\",\"optional\":true,\"package\":\"http\",\"req\":\"^0.2\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"native-tls\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"once_cell\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"ring\",\"logging\",\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.19\"},{\"default_features\":false,\"features\":[\"std\",\"ring\"],\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23.5\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"rustls-pemfile\",\"req\":\"^2.0\"},{\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.97\"},{\"name\":\"socks\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"url\",\"req\":\"^2.5.0\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^0.26\"}],\"features\":{\"brotli\":[\"dep:brotli-decompressor\"],\"charset\":[\"dep:encoding_rs\"],\"cookies\":[\"dep:cookie\",\"dep:cookie_store\"],\"default\":[\"tls\",\"gzip\"],\"gzip\":[\"dep:flate2\"],\"http-crate\":[\"dep:http\"],\"http-interop\":[\"dep:http-02\"],\"json\":[\"dep:serde\",\"dep:serde_json\"],\"native-certs\":[\"dep:rustls-native-certs\"],\"native-tls\":[\"dep:native-tls\"],\"proxy-from-env\":[],\"socks-proxy\":[\"dep:socks\"],\"testdeps\":[\"dep:hootbin\"],\"tls\":[\"dep:webpki-roots\",\"dep:rustls\",\"dep:rustls-pki-types\"]}}", "url_2.5.8": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"form_urlencoded\",\"req\":\"^1.2.2\"},{\"default_features\":false,\"features\":[\"alloc\",\"compiled_data\"],\"name\":\"idna\",\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"percent-encoding\",\"req\":\"^2.3.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"}],\"features\":{\"debugger_visualizer\":[],\"default\":[\"std\"],\"expose_internals\":[],\"serde\":[\"dep:serde\",\"dep:serde_derive\"],\"std\":[\"idna/std\",\"percent-encoding/std\",\"form_urlencoded/std\",\"serde?/std\"]}}", "urlencoding_2.1.3": "{\"dependencies\":[],\"features\":{}}", "utf8-width_0.1.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"}],\"features\":{}}", @@ -1342,34 +1267,47 @@ "valuable_0.1.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"name\":\"valuable-derive\",\"optional\":true,\"req\":\"=0.1.1\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"derive\":[\"valuable-derive\"],\"std\":[\"alloc\"]}}", "version_check_0.9.5": "{\"dependencies\":[],\"features\":{}}", "vsimd_0.8.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"const-str\",\"req\":\"^0.5.3\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.8\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.33\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"}],\"features\":{\"alloc\":[],\"detect\":[\"std\"],\"std\":[\"alloc\"],\"unstable\":[]}}", - "waker-fn_1.2.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"portable-atomic-util\",\"optional\":true,\"req\":\"^0.2\"}],\"features\":{\"portable-atomic\":[\"portable-atomic-util\"]}}", "walkdir_2.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"same-file\",\"req\":\"^1.0.1\"},{\"name\":\"winapi-util\",\"req\":\"^0.1.1\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "walrus-macro_0.24.0": "{\"dependencies\":[{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.86\"},{\"name\":\"quote\",\"req\":\"^1.0.37\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.77\"}],\"features\":{}}", + "walrus_0.24.5": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11.0\"},{\"name\":\"gimli\",\"req\":\"^0.26.0\"},{\"name\":\"id-arena\",\"req\":\"^2.2.1\"},{\"name\":\"leb128\",\"req\":\"^0.2.4\"},{\"name\":\"log\",\"req\":\"^0.4.8\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.1.0\"},{\"name\":\"walrus-macro\",\"req\":\"=0.24.0\"},{\"name\":\"wasm-encoder\",\"req\":\"^0.240.0\"},{\"name\":\"wasmparser\",\"req\":\"^0.240.0\"}],\"features\":{\"parallel\":[\"rayon\",\"id-arena/rayon\"]}}", "want_0.3.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"tokio-executor\",\"req\":\"^0.2.0-alpha.2\"},{\"kind\":\"dev\",\"name\":\"tokio-sync\",\"req\":\"^0.2.0-alpha.2\"},{\"name\":\"try-lock\",\"req\":\"^0.2.4\"}],\"features\":{}}", "wasi_0.11.1+wasi-snapshot-preview1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\"],\"std\":[]}}", - "wasi_0.9.0+wasi-snapshot-preview1": "{\"dependencies\":[{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"rustc-dep-of-std\":[\"compiler_builtins\",\"core\",\"rustc-std-workspace-alloc\"],\"std\":[]}}", "wasip2_1.0.2+wasi-0.2.9": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"wit-bindgen\",\"req\":\"^0.51.0\"}],\"features\":{\"bitflags\":[\"wit-bindgen/bitflags\"],\"default\":[\"std\",\"bitflags\"],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"wit-bindgen/rustc-dep-of-std\"],\"std\":[]}}", "wasip2_1.0.3+wasi-0.2.9": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"wit-bindgen\",\"req\":\"^0.57.1\"}],\"features\":{\"bitflags\":[\"wit-bindgen/bitflags\"],\"default\":[\"std\",\"bitflags\"],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"wit-bindgen/rustc-dep-of-std\"],\"std\":[]}}", "wasip3_0.4.0+wasi-0.3.0-rc-2026-01-06": "{\"dependencies\":[{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.10.1\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.31\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^1.3.1\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1.0.1\"},{\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2.0.17\"},{\"default_features\":false,\"features\":[\"async\"],\"name\":\"wit-bindgen\",\"req\":\"^0.51.0\"},{\"default_features\":false,\"features\":[\"async-spawn\"],\"kind\":\"dev\",\"name\":\"wit-bindgen\",\"req\":\"^0.51.0\"}],\"features\":{\"http-compat\":[\"dep:bytes\",\"dep:http-body\",\"dep:http\",\"dep:thiserror\",\"wit-bindgen/async-spawn\"]}}", - "wasm-bindgen-backend_0.2.104": "{\"dependencies\":[{\"name\":\"bumpalo\",\"req\":\"^3.0.0\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.104\"}],\"features\":{\"extra-traits\":[\"syn/extra-traits\"]}}", - "wasm-bindgen-futures_0.4.54": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.8\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.81\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.104\"},{\"default_features\":false,\"features\":[\"MessageEvent\",\"Worker\"],\"name\":\"web-sys\",\"req\":\"=0.3.81\",\"target\":\"cfg(target_feature = \\\"atomics\\\")\"}],\"features\":{\"default\":[\"std\"],\"futures-core-03-stream\":[\"futures-core\"],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\",\"web-sys/std\"]}}", - "wasm-bindgen-macro-support_0.2.104": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"visit\",\"visit-mut\",\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"name\":\"wasm-bindgen-backend\",\"req\":\"=0.2.104\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.104\"}],\"features\":{\"extra-traits\":[\"syn/extra-traits\"],\"strict-macro\":[]}}", - "wasm-bindgen-macro_0.2.104": "{\"dependencies\":[{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro-support\",\"req\":\"=0.2.104\"}],\"features\":{\"strict-macro\":[\"wasm-bindgen-macro-support/strict-macro\"]}}", - "wasm-bindgen-shared_0.2.104": "{\"dependencies\":[{\"name\":\"unicode-ident\",\"req\":\"^1.0.5\"}],\"features\":{}}", - "wasm-bindgen_0.2.104": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"build\",\"name\":\"rustversion-compat\",\"package\":\"rustversion\",\"req\":\"^1.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro\",\"req\":\"=0.2.104\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.104\"}],\"features\":{\"default\":[\"std\"],\"enable-interning\":[\"std\"],\"gg-alloc\":[],\"msrv\":[],\"rustversion\":[],\"serde-serialize\":[\"serde\",\"serde_json\",\"std\"],\"spans\":[],\"std\":[],\"strict-macro\":[\"wasm-bindgen-macro/strict-macro\"],\"xxx_debug_only_print_generated_code\":[]}}", + "wasm-bindgen-cli-support_0.2.105": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"leb128\",\"req\":\"^0.2\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"name\":\"rustc-demangle\",\"req\":\"^0.1.13\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"parallel\"],\"name\":\"walrus\",\"req\":\"^0.24.2\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.105\"},{\"name\":\"wasmparser\",\"req\":\"^0.214\"},{\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.214\"},{\"kind\":\"dev\",\"name\":\"wast\",\"req\":\"^214\"},{\"kind\":\"dev\",\"name\":\"wat\",\"req\":\"^1.0\"}],\"features\":{}}", + "wasm-bindgen-cli_0.2.105": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"assert_cmd\",\"req\":\"^2\"},{\"features\":[\"derive\"],\"name\":\"clap\",\"req\":\"^4\"},{\"name\":\"env_logger\",\"req\":\"^0.11.5\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"native-tls\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"predicates\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.11.2\"},{\"default_features\":false,\"name\":\"rouille\",\"req\":\"^3.0.0\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"shlex\",\"req\":\"^1\"},{\"name\":\"tempfile\",\"req\":\"^3.0\"},{\"default_features\":false,\"features\":[\"brotli\",\"gzip\"],\"name\":\"ureq\",\"req\":\"^2.7\"},{\"name\":\"walrus\",\"req\":\"^0.24.2\"},{\"name\":\"wasm-bindgen-cli-support\",\"req\":\"=0.2.105\"},{\"kind\":\"dev\",\"name\":\"wasmparser\",\"req\":\"^0.214\"},{\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.214\"}],\"features\":{\"default\":[\"rustls-tls\"],\"native-tls\":[\"ureq/native-tls\"],\"openssl\":[\"dep:native-tls\"],\"rustls-tls\":[\"ureq/tls\"],\"vendored-openssl\":[\"openssl\",\"native-tls/vendored\"]}}", + "wasm-bindgen-futures_0.4.55": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.8\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.82\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"},{\"default_features\":false,\"features\":[\"MessageEvent\",\"Worker\"],\"name\":\"web-sys\",\"req\":\"=0.3.82\",\"target\":\"cfg(target_feature = \\\"atomics\\\")\"}],\"features\":{\"default\":[\"std\"],\"futures-core-03-stream\":[\"futures-core\"],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\",\"web-sys/std\"]}}", + "wasm-bindgen-futures_0.4.75": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.102\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.125\"}],\"features\":{\"default\":[\"std\"],\"futures-core-03-stream\":[\"js-sys/futures-core-03-stream\"],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\"]}}", + "wasm-bindgen-macro-support_0.2.105": "{\"dependencies\":[{\"name\":\"bumpalo\",\"req\":\"^3.0.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"visit\",\"visit-mut\",\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.105\"}],\"features\":{\"extra-traits\":[\"syn/extra-traits\"],\"strict-macro\":[]}}", + "wasm-bindgen-macro-support_0.2.125": "{\"dependencies\":[{\"name\":\"bumpalo\",\"req\":\"^3.0.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"visit\",\"visit-mut\",\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.125\"}],\"features\":{\"extra-traits\":[\"syn/extra-traits\"],\"strict-macro\":[]}}", + "wasm-bindgen-macro_0.2.105": "{\"dependencies\":[{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro-support\",\"req\":\"=0.2.105\"}],\"features\":{\"strict-macro\":[\"wasm-bindgen-macro-support/strict-macro\"]}}", + "wasm-bindgen-macro_0.2.125": "{\"dependencies\":[{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro-support\",\"req\":\"=0.2.125\"}],\"features\":{\"strict-macro\":[\"wasm-bindgen-macro-support/strict-macro\"]}}", + "wasm-bindgen-shared_0.2.105": "{\"dependencies\":[{\"name\":\"unicode-ident\",\"req\":\"^1.0.5\"}],\"features\":{}}", + "wasm-bindgen-shared_0.2.125": "{\"dependencies\":[{\"name\":\"unicode-ident\",\"req\":\"^1.0.5\"}],\"features\":{}}", + "wasm-bindgen-test-macro_0.3.55": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"parsing\",\"proc-macro\",\"derive\",\"printing\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"}],\"features\":{}}", + "wasm-bindgen-test_0.3.55": "{\"dependencies\":[{\"name\":\"gg-alloc\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.82\"},{\"name\":\"minicov\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", wasm_bindgen_unstable_test_coverage))\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"},{\"default_features\":false,\"name\":\"wasm-bindgen-futures\",\"req\":\"=0.4.55\"},{\"name\":\"wasm-bindgen-test-macro\",\"req\":\"=0.3.55\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\",\"wasm-bindgen-futures/std\"]}}", + "wasm-bindgen_0.2.105": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"build\",\"name\":\"rustversion-compat\",\"package\":\"rustversion\",\"req\":\"^1.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro\",\"req\":\"=0.2.105\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.105\"}],\"features\":{\"default\":[\"std\"],\"enable-interning\":[\"std\"],\"gg-alloc\":[],\"msrv\":[],\"rustversion\":[],\"serde-serialize\":[\"serde\",\"serde_json\",\"std\"],\"spans\":[],\"std\":[],\"strict-macro\":[\"wasm-bindgen-macro/strict-macro\"],\"xxx_debug_only_print_generated_code\":[]}}", + "wasm-bindgen_0.2.125": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm64\\\")\"},{\"kind\":\"build\",\"name\":\"rustversion-compat\",\"package\":\"rustversion\",\"req\":\"^1.0.6\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm64\\\")\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro\",\"req\":\"=0.2.125\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.125\"}],\"features\":{\"default\":[\"std\"],\"enable-interning\":[\"std\"],\"gg-alloc\":[],\"msrv\":[],\"rustversion\":[],\"serde-serialize\":[\"serde\",\"serde_json\",\"std\"],\"spans\":[],\"std\":[],\"strict-macro\":[\"wasm-bindgen-macro/strict-macro\"],\"xxx_debug_only_print_generated_code\":[]}}", + "wasm-encoder_0.240.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"default_features\":false,\"name\":\"leb128fmt\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.2.0\"},{\"default_features\":false,\"features\":[\"simd\",\"simd\"],\"name\":\"wasmparser\",\"optional\":true,\"req\":\"^0.240.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.240.0\"}],\"features\":{\"component-model\":[\"wasmparser?/component-model\"],\"default\":[\"std\",\"component-model\"],\"std\":[\"wasmparser?/std\"]}}", "wasm-encoder_0.244.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"default_features\":false,\"name\":\"leb128fmt\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.2.0\"},{\"default_features\":false,\"features\":[\"simd\",\"simd\"],\"name\":\"wasmparser\",\"optional\":true,\"req\":\"^0.244.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.244.0\"}],\"features\":{\"component-model\":[\"wasmparser?/component-model\"],\"default\":[\"std\",\"component-model\"],\"std\":[\"wasmparser?/std\"]}}", "wasm-metadata_0.244.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"auditable-serde\",\"optional\":true,\"req\":\"^0.8.0\"},{\"features\":[\"derive\"],\"name\":\"clap\",\"optional\":true,\"req\":\"^4.0.0\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"indexmap\",\"req\":\"^2.7.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0.166\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"spdx\",\"optional\":true,\"req\":\"^0.10.1\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"features\":[\"std\",\"component-model\"],\"name\":\"wasm-encoder\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"simd\",\"std\",\"component-model\",\"hash-collections\"],\"name\":\"wasmparser\",\"req\":\"^0.244.0\"}],\"features\":{\"default\":[\"oci\",\"serde\"],\"oci\":[\"dep:auditable-serde\",\"dep:flate2\",\"dep:url\",\"dep:spdx\",\"dep:serde_json\",\"serde\"],\"serde\":[\"dep:serde_derive\",\"dep:serde\"]}}", - "wasm-streams_0.4.2": "{\"dependencies\":[{\"features\":[\"io\",\"sink\"],\"name\":\"futures-util\",\"req\":\"^0.3.31\"},{\"features\":[\"futures\"],\"kind\":\"dev\",\"name\":\"gloo-timers\",\"req\":\"^0.3.0\"},{\"name\":\"js-sys\",\"req\":\"^0.3.72\"},{\"kind\":\"dev\",\"name\":\"pin-project\",\"req\":\"^1\"},{\"features\":[\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"wasm-bindgen\",\"req\":\"^0.2.95\"},{\"name\":\"wasm-bindgen-futures\",\"req\":\"^0.4.45\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.45\"},{\"features\":[\"AbortSignal\",\"QueuingStrategy\",\"ReadableStream\",\"ReadableStreamType\",\"ReadableWritablePair\",\"ReadableStreamByobReader\",\"ReadableStreamReaderMode\",\"ReadableStreamReadResult\",\"ReadableStreamByobRequest\",\"ReadableStreamDefaultReader\",\"ReadableByteStreamController\",\"ReadableStreamGetReaderOptions\",\"ReadableStreamDefaultController\",\"StreamPipeOptions\",\"TransformStream\",\"TransformStreamDefaultController\",\"Transformer\",\"UnderlyingSink\",\"UnderlyingSource\",\"WritableStream\",\"WritableStreamDefaultController\",\"WritableStreamDefaultWriter\"],\"name\":\"web-sys\",\"req\":\"^0.3.72\"},{\"features\":[\"console\",\"AbortSignal\",\"ErrorEvent\",\"PromiseRejectionEvent\",\"Response\",\"ReadableStream\",\"Window\"],\"kind\":\"dev\",\"name\":\"web-sys\",\"req\":\"^0.3.72\"}],\"features\":{}}", + "wasm-streams_0.5.0": "{\"dependencies\":[{\"features\":[\"io\",\"sink\"],\"name\":\"futures-util\",\"req\":\"^0.3.31\"},{\"features\":[\"futures\"],\"kind\":\"dev\",\"name\":\"gloo-timers\",\"req\":\"^0.3.0\"},{\"name\":\"js-sys\",\"req\":\"^0.3.85\"},{\"kind\":\"dev\",\"name\":\"pin-project\",\"req\":\"^1\"},{\"features\":[\"macros\",\"rt\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"wasm-bindgen\",\"req\":\"^0.2.108\"},{\"name\":\"wasm-bindgen-futures\",\"req\":\"^0.4.58\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.58\"},{\"features\":[\"AbortSignal\",\"QueuingStrategy\",\"ReadableStream\",\"ReadableStreamType\",\"ReadableWritablePair\",\"ReadableStreamByobReader\",\"ReadableStreamReaderMode\",\"ReadableStreamReadResult\",\"ReadableStreamByobRequest\",\"ReadableStreamDefaultReader\",\"ReadableByteStreamController\",\"ReadableStreamGetReaderOptions\",\"ReadableStreamDefaultController\",\"StreamPipeOptions\",\"TransformStream\",\"TransformStreamDefaultController\",\"Transformer\",\"UnderlyingSink\",\"UnderlyingSource\",\"WritableStream\",\"WritableStreamDefaultController\",\"WritableStreamDefaultWriter\"],\"name\":\"web-sys\",\"req\":\"^0.3.85\"},{\"features\":[\"console\",\"AbortSignal\",\"ErrorEvent\",\"PromiseRejectionEvent\",\"Response\",\"ReadableStream\",\"Window\"],\"kind\":\"dev\",\"name\":\"web-sys\",\"req\":\"^0.3.85\"}],\"features\":{}}", + "wasmparser_0.214.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.8.11\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.4.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"ahash\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.14.3\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"semver\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"}],\"features\":{\"default\":[\"std\",\"validate\",\"serde\"],\"no-hash-maps\":[],\"serde\":[\"dep:serde\",\"indexmap/serde\",\"hashbrown/serde\"],\"std\":[\"indexmap/std\"],\"validate\":[\"dep:indexmap\",\"dep:semver\",\"dep:hashbrown\",\"dep:ahash\"]}}", + "wasmparser_0.240.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.4.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.7.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"semver\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"}],\"features\":{\"component-model\":[\"dep:semver\"],\"default\":[\"std\",\"validate\",\"serde\",\"features\",\"component-model\",\"hash-collections\",\"simd\"],\"features\":[],\"hash-collections\":[\"dep:hashbrown\",\"dep:indexmap\"],\"prefer-btree-collections\":[],\"serde\":[\"dep:serde\",\"indexmap?/serde\",\"hashbrown?/serde\"],\"simd\":[],\"std\":[\"indexmap?/std\"],\"validate\":[]}}", "wasmparser_0.244.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.4.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.7.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"semver\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"}],\"features\":{\"component-model\":[\"dep:semver\"],\"default\":[\"std\",\"validate\",\"serde\",\"features\",\"component-model\",\"hash-collections\",\"simd\"],\"features\":[],\"hash-collections\":[\"dep:hashbrown\",\"dep:indexmap\"],\"prefer-btree-collections\":[],\"serde\":[\"dep:serde\",\"indexmap?/serde\",\"hashbrown?/serde\"],\"simd\":[],\"std\":[\"indexmap?/std\"],\"validate\":[]}}", - "web-sys_0.3.81": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.81\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.104\"}],\"features\":{\"AbortController\":[],\"AbortSignal\":[\"EventTarget\"],\"AddEventListenerOptions\":[],\"AesCbcParams\":[],\"AesCtrParams\":[],\"AesDerivedKeyParams\":[],\"AesGcmParams\":[],\"AesKeyAlgorithm\":[],\"AesKeyGenParams\":[],\"Algorithm\":[],\"AlignSetting\":[],\"AllowedBluetoothDevice\":[],\"AllowedUsbDevice\":[],\"AlphaOption\":[],\"AnalyserNode\":[\"AudioNode\",\"EventTarget\"],\"AnalyserOptions\":[],\"AngleInstancedArrays\":[],\"Animation\":[\"EventTarget\"],\"AnimationEffect\":[],\"AnimationEvent\":[\"Event\"],\"AnimationEventInit\":[],\"AnimationPlayState\":[],\"AnimationPlaybackEvent\":[\"Event\"],\"AnimationPlaybackEventInit\":[],\"AnimationPropertyDetails\":[],\"AnimationPropertyValueDetails\":[],\"AnimationTimeline\":[],\"AssignedNodesOptions\":[],\"AttestationConveyancePreference\":[],\"Attr\":[\"EventTarget\",\"Node\"],\"AttributeNameValue\":[],\"AudioBuffer\":[],\"AudioBufferOptions\":[],\"AudioBufferSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"AudioBufferSourceOptions\":[],\"AudioConfiguration\":[],\"AudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"AudioContextLatencyCategory\":[],\"AudioContextOptions\":[],\"AudioContextState\":[],\"AudioData\":[],\"AudioDataCopyToOptions\":[],\"AudioDataInit\":[],\"AudioDecoder\":[],\"AudioDecoderConfig\":[],\"AudioDecoderInit\":[],\"AudioDecoderSupport\":[],\"AudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"AudioEncoder\":[],\"AudioEncoderConfig\":[],\"AudioEncoderInit\":[],\"AudioEncoderSupport\":[],\"AudioListener\":[],\"AudioNode\":[\"EventTarget\"],\"AudioNodeOptions\":[],\"AudioParam\":[],\"AudioParamMap\":[],\"AudioProcessingEvent\":[\"Event\"],\"AudioSampleFormat\":[],\"AudioScheduledSourceNode\":[\"AudioNode\",\"EventTarget\"],\"AudioSinkInfo\":[],\"AudioSinkOptions\":[],\"AudioSinkType\":[],\"AudioStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"AudioTrack\":[],\"AudioTrackList\":[\"EventTarget\"],\"AudioWorklet\":[\"Worklet\"],\"AudioWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"AudioWorkletNode\":[\"AudioNode\",\"EventTarget\"],\"AudioWorkletNodeOptions\":[],\"AudioWorkletProcessor\":[],\"AuthenticationExtensionsClientInputs\":[],\"AuthenticationExtensionsClientInputsJson\":[],\"AuthenticationExtensionsClientOutputs\":[],\"AuthenticationExtensionsClientOutputsJson\":[],\"AuthenticationExtensionsDevicePublicKeyInputs\":[],\"AuthenticationExtensionsDevicePublicKeyOutputs\":[],\"AuthenticationExtensionsLargeBlobInputs\":[],\"AuthenticationExtensionsLargeBlobOutputs\":[],\"AuthenticationExtensionsPrfInputs\":[],\"AuthenticationExtensionsPrfOutputs\":[],\"AuthenticationExtensionsPrfValues\":[],\"AuthenticationResponseJson\":[],\"AuthenticatorAssertionResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAssertionResponseJson\":[],\"AuthenticatorAttachment\":[],\"AuthenticatorAttestationResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAttestationResponseJson\":[],\"AuthenticatorResponse\":[],\"AuthenticatorSelectionCriteria\":[],\"AuthenticatorTransport\":[],\"AutoKeyword\":[],\"AutocompleteInfo\":[],\"BarProp\":[],\"BaseAudioContext\":[\"EventTarget\"],\"BaseComputedKeyframe\":[],\"BaseKeyframe\":[],\"BasePropertyIndexedKeyframe\":[],\"BasicCardRequest\":[],\"BasicCardResponse\":[],\"BasicCardType\":[],\"BatteryManager\":[\"EventTarget\"],\"BeforeUnloadEvent\":[\"Event\"],\"BinaryType\":[],\"BiquadFilterNode\":[\"AudioNode\",\"EventTarget\"],\"BiquadFilterOptions\":[],\"BiquadFilterType\":[],\"Blob\":[],\"BlobEvent\":[\"Event\"],\"BlobEventInit\":[],\"BlobPropertyBag\":[],\"BlockParsingOptions\":[],\"Bluetooth\":[\"EventTarget\"],\"BluetoothAdvertisingEvent\":[\"Event\"],\"BluetoothAdvertisingEventInit\":[],\"BluetoothCharacteristicProperties\":[],\"BluetoothDataFilterInit\":[],\"BluetoothDevice\":[\"EventTarget\"],\"BluetoothLeScanFilterInit\":[],\"BluetoothManufacturerDataMap\":[],\"BluetoothPermissionDescriptor\":[],\"BluetoothPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"BluetoothPermissionStorage\":[],\"BluetoothRemoteGattCharacteristic\":[\"EventTarget\"],\"BluetoothRemoteGattDescriptor\":[],\"BluetoothRemoteGattServer\":[],\"BluetoothRemoteGattService\":[\"EventTarget\"],\"BluetoothServiceDataMap\":[],\"BluetoothUuid\":[],\"BoxQuadOptions\":[],\"BroadcastChannel\":[\"EventTarget\"],\"BrowserElementDownloadOptions\":[],\"BrowserElementExecuteScriptOptions\":[],\"BrowserFeedWriter\":[],\"BrowserFindCaseSensitivity\":[],\"BrowserFindDirection\":[],\"ByteLengthQueuingStrategy\":[],\"Cache\":[],\"CacheBatchOperation\":[],\"CacheQueryOptions\":[],\"CacheStorage\":[],\"CacheStorageNamespace\":[],\"CanvasCaptureMediaStream\":[\"EventTarget\",\"MediaStream\"],\"CanvasCaptureMediaStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"CanvasGradient\":[],\"CanvasPattern\":[],\"CanvasRenderingContext2d\":[],\"CanvasWindingRule\":[],\"CaretChangedReason\":[],\"CaretPosition\":[],\"CaretStateChangedEventInit\":[],\"CdataSection\":[\"CharacterData\",\"EventTarget\",\"Node\",\"Text\"],\"ChannelCountMode\":[],\"ChannelInterpretation\":[],\"ChannelMergerNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelMergerOptions\":[],\"ChannelSplitterNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelSplitterOptions\":[],\"CharacterData\":[\"EventTarget\",\"Node\"],\"CheckerboardReason\":[],\"CheckerboardReport\":[],\"CheckerboardReportService\":[],\"ChromeFilePropertyBag\":[],\"ChromeWorker\":[\"EventTarget\",\"Worker\"],\"Client\":[],\"ClientQueryOptions\":[],\"ClientRectsAndTexts\":[],\"ClientType\":[],\"Clients\":[],\"Clipboard\":[\"EventTarget\"],\"ClipboardEvent\":[\"Event\"],\"ClipboardEventInit\":[],\"ClipboardItem\":[],\"ClipboardItemOptions\":[],\"ClipboardPermissionDescriptor\":[],\"ClipboardUnsanitizedFormats\":[],\"CloseEvent\":[\"Event\"],\"CloseEventInit\":[],\"CodecState\":[],\"CollectedClientData\":[],\"ColorSpaceConversion\":[],\"Comment\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"CompositeOperation\":[],\"CompositionEvent\":[\"Event\",\"UiEvent\"],\"CompositionEventInit\":[],\"CompressionFormat\":[],\"CompressionStream\":[],\"ComputedEffectTiming\":[],\"ConnStatusDict\":[],\"ConnectionType\":[],\"ConsoleCounter\":[],\"ConsoleCounterError\":[],\"ConsoleEvent\":[],\"ConsoleInstance\":[],\"ConsoleInstanceOptions\":[],\"ConsoleLevel\":[],\"ConsoleLogLevel\":[],\"ConsoleProfileEvent\":[],\"ConsoleStackEntry\":[],\"ConsoleTimerError\":[],\"ConsoleTimerLogOrEnd\":[],\"ConsoleTimerStart\":[],\"ConstantSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"ConstantSourceOptions\":[],\"ConstrainBooleanParameters\":[],\"ConstrainDomStringParameters\":[],\"ConstrainDoubleRange\":[],\"ConstrainLongRange\":[],\"ContextAttributes2d\":[],\"ConvertCoordinateOptions\":[],\"ConvolverNode\":[\"AudioNode\",\"EventTarget\"],\"ConvolverOptions\":[],\"Coordinates\":[],\"CountQueuingStrategy\":[],\"Credential\":[],\"CredentialCreationOptions\":[],\"CredentialPropertiesOutput\":[],\"CredentialRequestOptions\":[],\"CredentialsContainer\":[],\"Crypto\":[],\"CryptoKey\":[],\"CryptoKeyPair\":[],\"CssAnimation\":[\"Animation\",\"EventTarget\"],\"CssBoxType\":[],\"CssConditionRule\":[\"CssGroupingRule\",\"CssRule\"],\"CssCounterStyleRule\":[\"CssRule\"],\"CssFontFaceRule\":[\"CssRule\"],\"CssFontFeatureValuesRule\":[\"CssRule\"],\"CssGroupingRule\":[\"CssRule\"],\"CssImportRule\":[\"CssRule\"],\"CssKeyframeRule\":[\"CssRule\"],\"CssKeyframesRule\":[\"CssRule\"],\"CssMediaRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssNamespaceRule\":[\"CssRule\"],\"CssPageRule\":[\"CssRule\"],\"CssPseudoElement\":[],\"CssRule\":[],\"CssRuleList\":[],\"CssStyleDeclaration\":[],\"CssStyleRule\":[\"CssRule\"],\"CssStyleSheet\":[\"StyleSheet\"],\"CssStyleSheetParsingMode\":[],\"CssSupportsRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssTransition\":[\"Animation\",\"EventTarget\"],\"CustomElementRegistry\":[],\"CustomEvent\":[\"Event\"],\"CustomEventInit\":[],\"DataTransfer\":[],\"DataTransferItem\":[],\"DataTransferItemList\":[],\"DateTimeValue\":[],\"DecoderDoctorNotification\":[],\"DecoderDoctorNotificationType\":[],\"DecompressionStream\":[],\"DedicatedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"DelayNode\":[\"AudioNode\",\"EventTarget\"],\"DelayOptions\":[],\"DeviceAcceleration\":[],\"DeviceAccelerationInit\":[],\"DeviceLightEvent\":[\"Event\"],\"DeviceLightEventInit\":[],\"DeviceMotionEvent\":[\"Event\"],\"DeviceMotionEventInit\":[],\"DeviceOrientationEvent\":[\"Event\"],\"DeviceOrientationEventInit\":[],\"DeviceProximityEvent\":[\"Event\"],\"DeviceProximityEventInit\":[],\"DeviceRotationRate\":[],\"DeviceRotationRateInit\":[],\"DhKeyDeriveParams\":[],\"DirectionSetting\":[],\"Directory\":[],\"DirectoryPickerOptions\":[],\"DisplayMediaStreamConstraints\":[],\"DisplayNameOptions\":[],\"DisplayNameResult\":[],\"DistanceModelType\":[],\"DnsCacheDict\":[],\"DnsCacheEntry\":[],\"DnsLookupDict\":[],\"Document\":[\"EventTarget\",\"Node\"],\"DocumentFragment\":[\"EventTarget\",\"Node\"],\"DocumentTimeline\":[\"AnimationTimeline\"],\"DocumentTimelineOptions\":[],\"DocumentType\":[\"EventTarget\",\"Node\"],\"DomError\":[],\"DomException\":[],\"DomImplementation\":[],\"DomMatrix\":[\"DomMatrixReadOnly\"],\"DomMatrix2dInit\":[],\"DomMatrixInit\":[],\"DomMatrixReadOnly\":[],\"DomParser\":[],\"DomPoint\":[\"DomPointReadOnly\"],\"DomPointInit\":[],\"DomPointReadOnly\":[],\"DomQuad\":[],\"DomQuadInit\":[],\"DomQuadJson\":[],\"DomRect\":[\"DomRectReadOnly\"],\"DomRectInit\":[],\"DomRectList\":[],\"DomRectReadOnly\":[],\"DomRequest\":[\"EventTarget\"],\"DomRequestReadyState\":[],\"DomStringList\":[],\"DomStringMap\":[],\"DomTokenList\":[],\"DomWindowResizeEventDetail\":[],\"DoubleRange\":[],\"DragEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"DragEventInit\":[],\"DynamicsCompressorNode\":[\"AudioNode\",\"EventTarget\"],\"DynamicsCompressorOptions\":[],\"EcKeyAlgorithm\":[],\"EcKeyGenParams\":[],\"EcKeyImportParams\":[],\"EcdhKeyDeriveParams\":[],\"EcdsaParams\":[],\"EffectTiming\":[],\"Element\":[\"EventTarget\",\"Node\"],\"ElementCreationOptions\":[],\"ElementDefinitionOptions\":[],\"EncodedAudioChunk\":[],\"EncodedAudioChunkInit\":[],\"EncodedAudioChunkMetadata\":[],\"EncodedAudioChunkType\":[],\"EncodedVideoChunk\":[],\"EncodedVideoChunkInit\":[],\"EncodedVideoChunkMetadata\":[],\"EncodedVideoChunkType\":[],\"EndingTypes\":[],\"ErrorCallback\":[],\"ErrorEvent\":[\"Event\"],\"ErrorEventInit\":[],\"Event\":[],\"EventInit\":[],\"EventListener\":[],\"EventListenerOptions\":[],\"EventModifierInit\":[],\"EventSource\":[\"EventTarget\"],\"EventSourceInit\":[],\"EventTarget\":[],\"Exception\":[],\"ExtBlendMinmax\":[],\"ExtColorBufferFloat\":[],\"ExtColorBufferHalfFloat\":[],\"ExtDisjointTimerQuery\":[],\"ExtFragDepth\":[],\"ExtSRgb\":[],\"ExtShaderTextureLod\":[],\"ExtTextureFilterAnisotropic\":[],\"ExtTextureNorm16\":[],\"ExtendableEvent\":[\"Event\"],\"ExtendableEventInit\":[],\"ExtendableMessageEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableMessageEventInit\":[],\"External\":[],\"FakePluginMimeEntry\":[],\"FakePluginTagInit\":[],\"FetchEvent\":[\"Event\",\"ExtendableEvent\"],\"FetchEventInit\":[],\"FetchObserver\":[\"EventTarget\"],\"FetchReadableStreamReadDataArray\":[],\"FetchReadableStreamReadDataDone\":[],\"FetchState\":[],\"File\":[\"Blob\"],\"FileCallback\":[],\"FileList\":[],\"FilePickerAcceptType\":[],\"FilePickerOptions\":[],\"FilePropertyBag\":[],\"FileReader\":[\"EventTarget\"],\"FileReaderSync\":[],\"FileSystem\":[],\"FileSystemCreateWritableOptions\":[],\"FileSystemDirectoryEntry\":[\"FileSystemEntry\"],\"FileSystemDirectoryHandle\":[\"FileSystemHandle\"],\"FileSystemDirectoryReader\":[],\"FileSystemEntriesCallback\":[],\"FileSystemEntry\":[],\"FileSystemEntryCallback\":[],\"FileSystemFileEntry\":[\"FileSystemEntry\"],\"FileSystemFileHandle\":[\"FileSystemHandle\"],\"FileSystemFlags\":[],\"FileSystemGetDirectoryOptions\":[],\"FileSystemGetFileOptions\":[],\"FileSystemHandle\":[],\"FileSystemHandleKind\":[],\"FileSystemHandlePermissionDescriptor\":[],\"FileSystemPermissionDescriptor\":[],\"FileSystemPermissionMode\":[],\"FileSystemReadWriteOptions\":[],\"FileSystemRemoveOptions\":[],\"FileSystemSyncAccessHandle\":[],\"FileSystemWritableFileStream\":[\"WritableStream\"],\"FillMode\":[],\"FlashClassification\":[],\"FlowControlType\":[],\"FocusEvent\":[\"Event\",\"UiEvent\"],\"FocusEventInit\":[],\"FocusOptions\":[],\"FontData\":[],\"FontFace\":[],\"FontFaceDescriptors\":[],\"FontFaceLoadStatus\":[],\"FontFaceSet\":[\"EventTarget\"],\"FontFaceSetIterator\":[],\"FontFaceSetIteratorResult\":[],\"FontFaceSetLoadEvent\":[\"Event\"],\"FontFaceSetLoadEventInit\":[],\"FontFaceSetLoadStatus\":[],\"FormData\":[],\"FrameType\":[],\"FuzzingFunctions\":[],\"GainNode\":[\"AudioNode\",\"EventTarget\"],\"GainOptions\":[],\"Gamepad\":[],\"GamepadButton\":[],\"GamepadEffectParameters\":[],\"GamepadEvent\":[\"Event\"],\"GamepadEventInit\":[],\"GamepadHand\":[],\"GamepadHapticActuator\":[],\"GamepadHapticActuatorType\":[],\"GamepadHapticEffectType\":[],\"GamepadHapticsResult\":[],\"GamepadMappingType\":[],\"GamepadPose\":[],\"GamepadTouch\":[],\"Geolocation\":[],\"GestureEvent\":[\"Event\",\"UiEvent\"],\"GetAnimationsOptions\":[],\"GetRootNodeOptions\":[],\"GetUserMediaRequest\":[],\"Gpu\":[],\"GpuAdapter\":[],\"GpuAdapterInfo\":[],\"GpuAddressMode\":[],\"GpuAutoLayoutMode\":[],\"GpuBindGroup\":[],\"GpuBindGroupDescriptor\":[],\"GpuBindGroupEntry\":[],\"GpuBindGroupLayout\":[],\"GpuBindGroupLayoutDescriptor\":[],\"GpuBindGroupLayoutEntry\":[],\"GpuBlendComponent\":[],\"GpuBlendFactor\":[],\"GpuBlendOperation\":[],\"GpuBlendState\":[],\"GpuBuffer\":[],\"GpuBufferBinding\":[],\"GpuBufferBindingLayout\":[],\"GpuBufferBindingType\":[],\"GpuBufferDescriptor\":[],\"GpuBufferMapState\":[],\"GpuCanvasAlphaMode\":[],\"GpuCanvasConfiguration\":[],\"GpuCanvasContext\":[],\"GpuCanvasToneMapping\":[],\"GpuCanvasToneMappingMode\":[],\"GpuColorDict\":[],\"GpuColorTargetState\":[],\"GpuCommandBuffer\":[],\"GpuCommandBufferDescriptor\":[],\"GpuCommandEncoder\":[],\"GpuCommandEncoderDescriptor\":[],\"GpuCompareFunction\":[],\"GpuCompilationInfo\":[],\"GpuCompilationMessage\":[],\"GpuCompilationMessageType\":[],\"GpuComputePassDescriptor\":[],\"GpuComputePassEncoder\":[],\"GpuComputePassTimestampWrites\":[],\"GpuComputePipeline\":[],\"GpuComputePipelineDescriptor\":[],\"GpuCopyExternalImageDestInfo\":[],\"GpuCopyExternalImageSourceInfo\":[],\"GpuCullMode\":[],\"GpuDepthStencilState\":[],\"GpuDevice\":[\"EventTarget\"],\"GpuDeviceDescriptor\":[],\"GpuDeviceLostInfo\":[],\"GpuDeviceLostReason\":[],\"GpuError\":[],\"GpuErrorFilter\":[],\"GpuExtent3dDict\":[],\"GpuExternalTexture\":[],\"GpuExternalTextureBindingLayout\":[],\"GpuExternalTextureDescriptor\":[],\"GpuFeatureName\":[],\"GpuFilterMode\":[],\"GpuFragmentState\":[],\"GpuFrontFace\":[],\"GpuIndexFormat\":[],\"GpuInternalError\":[\"GpuError\"],\"GpuLoadOp\":[],\"GpuMipmapFilterMode\":[],\"GpuMultisampleState\":[],\"GpuObjectDescriptorBase\":[],\"GpuOrigin2dDict\":[],\"GpuOrigin3dDict\":[],\"GpuOutOfMemoryError\":[\"GpuError\"],\"GpuPipelineDescriptorBase\":[],\"GpuPipelineError\":[\"DomException\"],\"GpuPipelineErrorInit\":[],\"GpuPipelineErrorReason\":[],\"GpuPipelineLayout\":[],\"GpuPipelineLayoutDescriptor\":[],\"GpuPowerPreference\":[],\"GpuPrimitiveState\":[],\"GpuPrimitiveTopology\":[],\"GpuProgrammableStage\":[],\"GpuQuerySet\":[],\"GpuQuerySetDescriptor\":[],\"GpuQueryType\":[],\"GpuQueue\":[],\"GpuQueueDescriptor\":[],\"GpuRenderBundle\":[],\"GpuRenderBundleDescriptor\":[],\"GpuRenderBundleEncoder\":[],\"GpuRenderBundleEncoderDescriptor\":[],\"GpuRenderPassColorAttachment\":[],\"GpuRenderPassDepthStencilAttachment\":[],\"GpuRenderPassDescriptor\":[],\"GpuRenderPassEncoder\":[],\"GpuRenderPassLayout\":[],\"GpuRenderPassTimestampWrites\":[],\"GpuRenderPipeline\":[],\"GpuRenderPipelineDescriptor\":[],\"GpuRequestAdapterOptions\":[],\"GpuSampler\":[],\"GpuSamplerBindingLayout\":[],\"GpuSamplerBindingType\":[],\"GpuSamplerDescriptor\":[],\"GpuShaderModule\":[],\"GpuShaderModuleCompilationHint\":[],\"GpuShaderModuleDescriptor\":[],\"GpuStencilFaceState\":[],\"GpuStencilOperation\":[],\"GpuStorageTextureAccess\":[],\"GpuStorageTextureBindingLayout\":[],\"GpuStoreOp\":[],\"GpuSupportedFeatures\":[],\"GpuSupportedLimits\":[],\"GpuTexelCopyBufferInfo\":[],\"GpuTexelCopyBufferLayout\":[],\"GpuTexelCopyTextureInfo\":[],\"GpuTexture\":[],\"GpuTextureAspect\":[],\"GpuTextureBindingLayout\":[],\"GpuTextureDescriptor\":[],\"GpuTextureDimension\":[],\"GpuTextureFormat\":[],\"GpuTextureSampleType\":[],\"GpuTextureView\":[],\"GpuTextureViewDescriptor\":[],\"GpuTextureViewDimension\":[],\"GpuUncapturedErrorEvent\":[\"Event\"],\"GpuUncapturedErrorEventInit\":[],\"GpuValidationError\":[\"GpuError\"],\"GpuVertexAttribute\":[],\"GpuVertexBufferLayout\":[],\"GpuVertexFormat\":[],\"GpuVertexState\":[],\"GpuVertexStepMode\":[],\"GroupedHistoryEventInit\":[],\"HalfOpenInfoDict\":[],\"HardwareAcceleration\":[],\"HashChangeEvent\":[\"Event\"],\"HashChangeEventInit\":[],\"Headers\":[],\"HeadersGuardEnum\":[],\"Hid\":[\"EventTarget\"],\"HidCollectionInfo\":[],\"HidConnectionEvent\":[\"Event\"],\"HidConnectionEventInit\":[],\"HidDevice\":[\"EventTarget\"],\"HidDeviceFilter\":[],\"HidDeviceRequestOptions\":[],\"HidInputReportEvent\":[\"Event\"],\"HidInputReportEventInit\":[],\"HidReportInfo\":[],\"HidReportItem\":[],\"HidUnitSystem\":[],\"HiddenPluginEventInit\":[],\"History\":[],\"HitRegionOptions\":[],\"HkdfParams\":[],\"HmacDerivedKeyParams\":[],\"HmacImportParams\":[],\"HmacKeyAlgorithm\":[],\"HmacKeyGenParams\":[],\"HtmlAllCollection\":[],\"HtmlAnchorElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAudioElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HtmlBaseElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBodyElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlButtonElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCanvasElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCollection\":[],\"HtmlDListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDetailsElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDialogElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDirectoryElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDivElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"HtmlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"HtmlEmbedElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFieldSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFontElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFormControlsCollection\":[\"HtmlCollection\"],\"HtmlFormElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadingElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHtmlElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlIFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlImageElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlInputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLabelElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLegendElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLiElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLinkElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMapElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMediaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuItemElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMetaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMeterElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlModElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlObjectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptGroupElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionsCollection\":[\"HtmlCollection\"],\"HtmlOutputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParagraphElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParamElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPictureElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPreElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlProgressElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlQuoteElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlScriptElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSelectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSlotElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSourceElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSpanElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlStyleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCaptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCellElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableColElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableRowElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableSectionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTemplateElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTextAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTimeElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTitleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTrackElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUnknownElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlVideoElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HttpConnDict\":[],\"HttpConnInfo\":[],\"HttpConnectionElement\":[],\"IdbCursor\":[],\"IdbCursorDirection\":[],\"IdbCursorWithValue\":[\"IdbCursor\"],\"IdbDatabase\":[\"EventTarget\"],\"IdbFactory\":[],\"IdbFileHandle\":[\"EventTarget\"],\"IdbFileMetadataParameters\":[],\"IdbFileRequest\":[\"DomRequest\",\"EventTarget\"],\"IdbIndex\":[],\"IdbIndexParameters\":[],\"IdbKeyRange\":[],\"IdbLocaleAwareKeyRange\":[\"IdbKeyRange\"],\"IdbMutableFile\":[\"EventTarget\"],\"IdbObjectStore\":[],\"IdbObjectStoreParameters\":[],\"IdbOpenDbOptions\":[],\"IdbOpenDbRequest\":[\"EventTarget\",\"IdbRequest\"],\"IdbRequest\":[\"EventTarget\"],\"IdbRequestReadyState\":[],\"IdbTransaction\":[\"EventTarget\"],\"IdbTransactionDurability\":[],\"IdbTransactionMode\":[],\"IdbTransactionOptions\":[],\"IdbVersionChangeEvent\":[\"Event\"],\"IdbVersionChangeEventInit\":[],\"IdleDeadline\":[],\"IdleRequestOptions\":[],\"IirFilterNode\":[\"AudioNode\",\"EventTarget\"],\"IirFilterOptions\":[],\"ImageBitmap\":[],\"ImageBitmapOptions\":[],\"ImageBitmapRenderingContext\":[],\"ImageCapture\":[],\"ImageCaptureError\":[],\"ImageCaptureErrorEvent\":[\"Event\"],\"ImageCaptureErrorEventInit\":[],\"ImageData\":[],\"ImageDecodeOptions\":[],\"ImageDecodeResult\":[],\"ImageDecoder\":[],\"ImageDecoderInit\":[],\"ImageEncodeOptions\":[],\"ImageOrientation\":[],\"ImageTrack\":[\"EventTarget\"],\"ImageTrackList\":[],\"InputDeviceInfo\":[\"MediaDeviceInfo\"],\"InputEvent\":[\"Event\",\"UiEvent\"],\"InputEventInit\":[],\"IntersectionObserver\":[],\"IntersectionObserverEntry\":[],\"IntersectionObserverEntryInit\":[],\"IntersectionObserverInit\":[],\"IntlUtils\":[],\"IsInputPendingOptions\":[],\"IterableKeyAndValueResult\":[],\"IterableKeyOrValueResult\":[],\"IterationCompositeOperation\":[],\"JsonWebKey\":[],\"KeyAlgorithm\":[],\"KeyEvent\":[],\"KeyFrameRequestEvent\":[\"Event\"],\"KeyIdsInitData\":[],\"KeyboardEvent\":[\"Event\",\"UiEvent\"],\"KeyboardEventInit\":[],\"KeyframeAnimationOptions\":[],\"KeyframeEffect\":[\"AnimationEffect\"],\"KeyframeEffectOptions\":[],\"L10nElement\":[],\"L10nValue\":[],\"LargeBlobSupport\":[],\"LatencyMode\":[],\"LifecycleCallbacks\":[],\"LineAlignSetting\":[],\"ListBoxObject\":[],\"LocalMediaStream\":[\"EventTarget\",\"MediaStream\"],\"LocaleInfo\":[],\"Location\":[],\"Lock\":[],\"LockInfo\":[],\"LockManager\":[],\"LockManagerSnapshot\":[],\"LockMode\":[],\"LockOptions\":[],\"MathMlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"MediaCapabilities\":[],\"MediaCapabilitiesInfo\":[],\"MediaConfiguration\":[],\"MediaDecodingConfiguration\":[],\"MediaDecodingType\":[],\"MediaDeviceInfo\":[],\"MediaDeviceKind\":[],\"MediaDevices\":[\"EventTarget\"],\"MediaElementAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaElementAudioSourceOptions\":[],\"MediaEncodingConfiguration\":[],\"MediaEncodingType\":[],\"MediaEncryptedEvent\":[\"Event\"],\"MediaError\":[],\"MediaImage\":[],\"MediaKeyError\":[\"Event\"],\"MediaKeyMessageEvent\":[\"Event\"],\"MediaKeyMessageEventInit\":[],\"MediaKeyMessageType\":[],\"MediaKeyNeededEventInit\":[],\"MediaKeySession\":[\"EventTarget\"],\"MediaKeySessionType\":[],\"MediaKeyStatus\":[],\"MediaKeyStatusMap\":[],\"MediaKeySystemAccess\":[],\"MediaKeySystemConfiguration\":[],\"MediaKeySystemMediaCapability\":[],\"MediaKeySystemStatus\":[],\"MediaKeys\":[],\"MediaKeysPolicy\":[],\"MediaKeysRequirement\":[],\"MediaList\":[],\"MediaMetadata\":[],\"MediaMetadataInit\":[],\"MediaPositionState\":[],\"MediaQueryList\":[\"EventTarget\"],\"MediaQueryListEvent\":[\"Event\"],\"MediaQueryListEventInit\":[],\"MediaRecorder\":[\"EventTarget\"],\"MediaRecorderErrorEvent\":[\"Event\"],\"MediaRecorderErrorEventInit\":[],\"MediaRecorderOptions\":[],\"MediaSession\":[],\"MediaSessionAction\":[],\"MediaSessionActionDetails\":[],\"MediaSessionPlaybackState\":[],\"MediaSource\":[\"EventTarget\"],\"MediaSourceEndOfStreamError\":[],\"MediaSourceEnum\":[],\"MediaSourceReadyState\":[],\"MediaStream\":[\"EventTarget\"],\"MediaStreamAudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceOptions\":[],\"MediaStreamConstraints\":[],\"MediaStreamError\":[],\"MediaStreamEvent\":[\"Event\"],\"MediaStreamEventInit\":[],\"MediaStreamTrack\":[\"EventTarget\"],\"MediaStreamTrackEvent\":[\"Event\"],\"MediaStreamTrackEventInit\":[],\"MediaStreamTrackGenerator\":[\"EventTarget\",\"MediaStreamTrack\"],\"MediaStreamTrackGeneratorInit\":[],\"MediaStreamTrackProcessor\":[],\"MediaStreamTrackProcessorInit\":[],\"MediaStreamTrackState\":[],\"MediaTrackCapabilities\":[],\"MediaTrackConstraintSet\":[],\"MediaTrackConstraints\":[],\"MediaTrackSettings\":[],\"MediaTrackSupportedConstraints\":[],\"MemoryAttribution\":[],\"MemoryAttributionContainer\":[],\"MemoryBreakdownEntry\":[],\"MemoryMeasurement\":[],\"MessageChannel\":[],\"MessageEvent\":[\"Event\"],\"MessageEventInit\":[],\"MessagePort\":[\"EventTarget\"],\"MidiAccess\":[\"EventTarget\"],\"MidiConnectionEvent\":[\"Event\"],\"MidiConnectionEventInit\":[],\"MidiInput\":[\"EventTarget\",\"MidiPort\"],\"MidiInputMap\":[],\"MidiMessageEvent\":[\"Event\"],\"MidiMessageEventInit\":[],\"MidiOptions\":[],\"MidiOutput\":[\"EventTarget\",\"MidiPort\"],\"MidiOutputMap\":[],\"MidiPort\":[\"EventTarget\"],\"MidiPortConnectionState\":[],\"MidiPortDeviceState\":[],\"MidiPortType\":[],\"MimeType\":[],\"MimeTypeArray\":[],\"MouseEvent\":[\"Event\",\"UiEvent\"],\"MouseEventInit\":[],\"MouseScrollEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"MozDebug\":[],\"MutationEvent\":[\"Event\"],\"MutationObserver\":[],\"MutationObserverInit\":[],\"MutationObservingInfo\":[],\"MutationRecord\":[],\"NamedNodeMap\":[],\"NativeOsFileReadOptions\":[],\"NativeOsFileWriteAtomicOptions\":[],\"NavigationType\":[],\"Navigator\":[],\"NavigatorAutomationInformation\":[],\"NavigatorUaBrandVersion\":[],\"NavigatorUaData\":[],\"NetworkCommandOptions\":[],\"NetworkInformation\":[\"EventTarget\"],\"NetworkResultOptions\":[],\"Node\":[\"EventTarget\"],\"NodeFilter\":[],\"NodeIterator\":[],\"NodeList\":[],\"Notification\":[\"EventTarget\"],\"NotificationAction\":[],\"NotificationDirection\":[],\"NotificationEvent\":[\"Event\",\"ExtendableEvent\"],\"NotificationEventInit\":[],\"NotificationOptions\":[],\"NotificationPermission\":[],\"ObserverCallback\":[],\"OesElementIndexUint\":[],\"OesStandardDerivatives\":[],\"OesTextureFloat\":[],\"OesTextureFloatLinear\":[],\"OesTextureHalfFloat\":[],\"OesTextureHalfFloatLinear\":[],\"OesVertexArrayObject\":[],\"OfflineAudioCompletionEvent\":[\"Event\"],\"OfflineAudioCompletionEventInit\":[],\"OfflineAudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"OfflineAudioContextOptions\":[],\"OfflineResourceList\":[\"EventTarget\"],\"OffscreenCanvas\":[\"EventTarget\"],\"OffscreenCanvasRenderingContext2d\":[],\"OpenFilePickerOptions\":[],\"OpenWindowEventDetail\":[],\"OptionalEffectTiming\":[],\"OrientationLockType\":[],\"OrientationType\":[],\"OscillatorNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"OscillatorOptions\":[],\"OscillatorType\":[],\"OverSampleType\":[],\"OvrMultiview2\":[],\"PageTransitionEvent\":[\"Event\"],\"PageTransitionEventInit\":[],\"PaintRequest\":[],\"PaintRequestList\":[],\"PaintWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"PannerNode\":[\"AudioNode\",\"EventTarget\"],\"PannerOptions\":[],\"PanningModelType\":[],\"ParityType\":[],\"Path2d\":[],\"PaymentAddress\":[],\"PaymentComplete\":[],\"PaymentMethodChangeEvent\":[\"Event\",\"PaymentRequestUpdateEvent\"],\"PaymentMethodChangeEventInit\":[],\"PaymentRequestUpdateEvent\":[\"Event\"],\"PaymentRequestUpdateEventInit\":[],\"PaymentResponse\":[],\"Pbkdf2Params\":[],\"PcImplIceConnectionState\":[],\"PcImplIceGatheringState\":[],\"PcImplSignalingState\":[],\"PcObserverStateType\":[],\"Performance\":[\"EventTarget\"],\"PerformanceEntry\":[],\"PerformanceEntryEventInit\":[],\"PerformanceEntryFilterOptions\":[],\"PerformanceMark\":[\"PerformanceEntry\"],\"PerformanceMeasure\":[\"PerformanceEntry\"],\"PerformanceNavigation\":[],\"PerformanceNavigationTiming\":[\"PerformanceEntry\",\"PerformanceResourceTiming\"],\"PerformanceObserver\":[],\"PerformanceObserverEntryList\":[],\"PerformanceObserverInit\":[],\"PerformanceResourceTiming\":[\"PerformanceEntry\"],\"PerformanceServerTiming\":[],\"PerformanceTiming\":[],\"PeriodicWave\":[],\"PeriodicWaveConstraints\":[],\"PeriodicWaveOptions\":[],\"PermissionDescriptor\":[],\"PermissionName\":[],\"PermissionState\":[],\"PermissionStatus\":[\"EventTarget\"],\"Permissions\":[],\"PictureInPictureEvent\":[\"Event\"],\"PictureInPictureEventInit\":[],\"PictureInPictureWindow\":[\"EventTarget\"],\"PlaneLayout\":[],\"PlaybackDirection\":[],\"Plugin\":[],\"PluginArray\":[],\"PluginCrashedEventInit\":[],\"PointerEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"PointerEventInit\":[],\"PopStateEvent\":[\"Event\"],\"PopStateEventInit\":[],\"PopupBlockedEvent\":[\"Event\"],\"PopupBlockedEventInit\":[],\"Position\":[],\"PositionAlignSetting\":[],\"PositionError\":[],\"PositionOptions\":[],\"PremultiplyAlpha\":[],\"Presentation\":[],\"PresentationAvailability\":[\"EventTarget\"],\"PresentationConnection\":[\"EventTarget\"],\"PresentationConnectionAvailableEvent\":[\"Event\"],\"PresentationConnectionAvailableEventInit\":[],\"PresentationConnectionBinaryType\":[],\"PresentationConnectionCloseEvent\":[\"Event\"],\"PresentationConnectionCloseEventInit\":[],\"PresentationConnectionClosedReason\":[],\"PresentationConnectionList\":[\"EventTarget\"],\"PresentationConnectionState\":[],\"PresentationReceiver\":[],\"PresentationRequest\":[\"EventTarget\"],\"PresentationStyle\":[],\"ProcessingInstruction\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"ProfileTimelineLayerRect\":[],\"ProfileTimelineMarker\":[],\"ProfileTimelineMessagePortOperationType\":[],\"ProfileTimelineStackFrame\":[],\"ProfileTimelineWorkerOperationType\":[],\"ProgressEvent\":[\"Event\"],\"ProgressEventInit\":[],\"PromiseNativeHandler\":[],\"PromiseRejectionEvent\":[\"Event\"],\"PromiseRejectionEventInit\":[],\"PublicKeyCredential\":[\"Credential\"],\"PublicKeyCredentialCreationOptions\":[],\"PublicKeyCredentialCreationOptionsJson\":[],\"PublicKeyCredentialDescriptor\":[],\"PublicKeyCredentialDescriptorJson\":[],\"PublicKeyCredentialEntity\":[],\"PublicKeyCredentialHints\":[],\"PublicKeyCredentialParameters\":[],\"PublicKeyCredentialRequestOptions\":[],\"PublicKeyCredentialRequestOptionsJson\":[],\"PublicKeyCredentialRpEntity\":[],\"PublicKeyCredentialType\":[],\"PublicKeyCredentialUserEntity\":[],\"PublicKeyCredentialUserEntityJson\":[],\"PushEncryptionKeyName\":[],\"PushEvent\":[\"Event\",\"ExtendableEvent\"],\"PushEventInit\":[],\"PushManager\":[],\"PushMessageData\":[],\"PushPermissionState\":[],\"PushSubscription\":[],\"PushSubscriptionInit\":[],\"PushSubscriptionJson\":[],\"PushSubscriptionKeys\":[],\"PushSubscriptionOptions\":[],\"PushSubscriptionOptionsInit\":[],\"QueryOptions\":[],\"QueuingStrategy\":[],\"QueuingStrategyInit\":[],\"RadioNodeList\":[\"NodeList\"],\"Range\":[],\"RcwnPerfStats\":[],\"RcwnStatus\":[],\"ReadableByteStreamController\":[],\"ReadableStream\":[],\"ReadableStreamByobReader\":[],\"ReadableStreamByobRequest\":[],\"ReadableStreamDefaultController\":[],\"ReadableStreamDefaultReader\":[],\"ReadableStreamGetReaderOptions\":[],\"ReadableStreamIteratorOptions\":[],\"ReadableStreamReadResult\":[],\"ReadableStreamReaderMode\":[],\"ReadableStreamType\":[],\"ReadableWritablePair\":[],\"RecordingState\":[],\"ReferrerPolicy\":[],\"RegisterRequest\":[],\"RegisterResponse\":[],\"RegisteredKey\":[],\"RegistrationOptions\":[],\"RegistrationResponseJson\":[],\"Request\":[],\"RequestCache\":[],\"RequestCredentials\":[],\"RequestDestination\":[],\"RequestDeviceOptions\":[],\"RequestInit\":[],\"RequestMediaKeySystemAccessNotification\":[],\"RequestMode\":[],\"RequestRedirect\":[],\"ResidentKeyRequirement\":[],\"ResizeObserver\":[],\"ResizeObserverBoxOptions\":[],\"ResizeObserverEntry\":[],\"ResizeObserverOptions\":[],\"ResizeObserverSize\":[],\"ResizeQuality\":[],\"Response\":[],\"ResponseInit\":[],\"ResponseType\":[],\"RsaHashedImportParams\":[],\"RsaOaepParams\":[],\"RsaOtherPrimesInfo\":[],\"RsaPssParams\":[],\"RtcAnswerOptions\":[],\"RtcBundlePolicy\":[],\"RtcCertificate\":[],\"RtcCertificateExpiration\":[],\"RtcCodecStats\":[],\"RtcConfiguration\":[],\"RtcDataChannel\":[\"EventTarget\"],\"RtcDataChannelEvent\":[\"Event\"],\"RtcDataChannelEventInit\":[],\"RtcDataChannelInit\":[],\"RtcDataChannelState\":[],\"RtcDataChannelType\":[],\"RtcDegradationPreference\":[],\"RtcEncodedAudioFrame\":[],\"RtcEncodedAudioFrameMetadata\":[],\"RtcEncodedAudioFrameOptions\":[],\"RtcEncodedVideoFrame\":[],\"RtcEncodedVideoFrameMetadata\":[],\"RtcEncodedVideoFrameOptions\":[],\"RtcEncodedVideoFrameType\":[],\"RtcFecParameters\":[],\"RtcIceCandidate\":[],\"RtcIceCandidateInit\":[],\"RtcIceCandidatePairStats\":[],\"RtcIceCandidateStats\":[],\"RtcIceComponentStats\":[],\"RtcIceConnectionState\":[],\"RtcIceCredentialType\":[],\"RtcIceGatheringState\":[],\"RtcIceServer\":[],\"RtcIceTransportPolicy\":[],\"RtcIdentityAssertion\":[],\"RtcIdentityAssertionResult\":[],\"RtcIdentityProvider\":[],\"RtcIdentityProviderDetails\":[],\"RtcIdentityProviderOptions\":[],\"RtcIdentityProviderRegistrar\":[],\"RtcIdentityValidationResult\":[],\"RtcInboundRtpStreamStats\":[],\"RtcMediaStreamStats\":[],\"RtcMediaStreamTrackStats\":[],\"RtcOfferAnswerOptions\":[],\"RtcOfferOptions\":[],\"RtcOutboundRtpStreamStats\":[],\"RtcPeerConnection\":[\"EventTarget\"],\"RtcPeerConnectionIceErrorEvent\":[\"Event\"],\"RtcPeerConnectionIceEvent\":[\"Event\"],\"RtcPeerConnectionIceEventInit\":[],\"RtcPeerConnectionState\":[],\"RtcPriorityType\":[],\"RtcRtcpParameters\":[],\"RtcRtpCapabilities\":[],\"RtcRtpCodecCapability\":[],\"RtcRtpCodecParameters\":[],\"RtcRtpContributingSource\":[],\"RtcRtpEncodingParameters\":[],\"RtcRtpHeaderExtensionCapability\":[],\"RtcRtpHeaderExtensionParameters\":[],\"RtcRtpParameters\":[],\"RtcRtpReceiver\":[],\"RtcRtpScriptTransform\":[],\"RtcRtpScriptTransformer\":[\"EventTarget\"],\"RtcRtpSender\":[],\"RtcRtpSourceEntry\":[],\"RtcRtpSourceEntryType\":[],\"RtcRtpSynchronizationSource\":[],\"RtcRtpTransceiver\":[],\"RtcRtpTransceiverDirection\":[],\"RtcRtpTransceiverInit\":[],\"RtcRtxParameters\":[],\"RtcSdpType\":[],\"RtcSessionDescription\":[],\"RtcSessionDescriptionInit\":[],\"RtcSignalingState\":[],\"RtcStats\":[],\"RtcStatsIceCandidatePairState\":[],\"RtcStatsIceCandidateType\":[],\"RtcStatsReport\":[],\"RtcStatsReportInternal\":[],\"RtcStatsType\":[],\"RtcTrackEvent\":[\"Event\"],\"RtcTrackEventInit\":[],\"RtcTransformEvent\":[\"Event\"],\"RtcTransportStats\":[],\"RtcdtmfSender\":[\"EventTarget\"],\"RtcdtmfToneChangeEvent\":[\"Event\"],\"RtcdtmfToneChangeEventInit\":[],\"RtcrtpContributingSourceStats\":[],\"RtcrtpStreamStats\":[],\"SFrameTransform\":[\"EventTarget\"],\"SFrameTransformErrorEvent\":[\"Event\"],\"SFrameTransformErrorEventInit\":[],\"SFrameTransformErrorEventType\":[],\"SFrameTransformOptions\":[],\"SFrameTransformRole\":[],\"SaveFilePickerOptions\":[],\"Scheduler\":[],\"SchedulerPostTaskOptions\":[],\"Scheduling\":[],\"Screen\":[\"EventTarget\"],\"ScreenColorGamut\":[],\"ScreenLuminance\":[],\"ScreenOrientation\":[\"EventTarget\"],\"ScriptProcessorNode\":[\"AudioNode\",\"EventTarget\"],\"ScrollAreaEvent\":[\"Event\",\"UiEvent\"],\"ScrollBehavior\":[],\"ScrollBoxObject\":[],\"ScrollIntoViewOptions\":[],\"ScrollLogicalPosition\":[],\"ScrollOptions\":[],\"ScrollRestoration\":[],\"ScrollSetting\":[],\"ScrollState\":[],\"ScrollToOptions\":[],\"ScrollViewChangeEventInit\":[],\"SecurityPolicyViolationEvent\":[\"Event\"],\"SecurityPolicyViolationEventDisposition\":[],\"SecurityPolicyViolationEventInit\":[],\"Selection\":[],\"SelectionMode\":[],\"Serial\":[\"EventTarget\"],\"SerialInputSignals\":[],\"SerialOptions\":[],\"SerialOutputSignals\":[],\"SerialPort\":[\"EventTarget\"],\"SerialPortFilter\":[],\"SerialPortInfo\":[],\"SerialPortRequestOptions\":[],\"ServerSocketOptions\":[],\"ServiceWorker\":[\"EventTarget\"],\"ServiceWorkerContainer\":[\"EventTarget\"],\"ServiceWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"ServiceWorkerRegistration\":[\"EventTarget\"],\"ServiceWorkerState\":[],\"ServiceWorkerUpdateViaCache\":[],\"ShadowRoot\":[\"DocumentFragment\",\"EventTarget\",\"Node\"],\"ShadowRootInit\":[],\"ShadowRootMode\":[],\"ShareData\":[],\"SharedWorker\":[\"EventTarget\"],\"SharedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"SignResponse\":[],\"SocketElement\":[],\"SocketOptions\":[],\"SocketReadyState\":[],\"SocketsDict\":[],\"SourceBuffer\":[\"EventTarget\"],\"SourceBufferAppendMode\":[],\"SourceBufferList\":[\"EventTarget\"],\"SpeechGrammar\":[],\"SpeechGrammarList\":[],\"SpeechRecognition\":[\"EventTarget\"],\"SpeechRecognitionAlternative\":[],\"SpeechRecognitionError\":[\"Event\"],\"SpeechRecognitionErrorCode\":[],\"SpeechRecognitionErrorInit\":[],\"SpeechRecognitionEvent\":[\"Event\"],\"SpeechRecognitionEventInit\":[],\"SpeechRecognitionResult\":[],\"SpeechRecognitionResultList\":[],\"SpeechSynthesis\":[\"EventTarget\"],\"SpeechSynthesisErrorCode\":[],\"SpeechSynthesisErrorEvent\":[\"Event\",\"SpeechSynthesisEvent\"],\"SpeechSynthesisErrorEventInit\":[],\"SpeechSynthesisEvent\":[\"Event\"],\"SpeechSynthesisEventInit\":[],\"SpeechSynthesisUtterance\":[\"EventTarget\"],\"SpeechSynthesisVoice\":[],\"StereoPannerNode\":[\"AudioNode\",\"EventTarget\"],\"StereoPannerOptions\":[],\"Storage\":[],\"StorageEstimate\":[],\"StorageEvent\":[\"Event\"],\"StorageEventInit\":[],\"StorageManager\":[],\"StorageType\":[],\"StreamPipeOptions\":[],\"StyleRuleChangeEventInit\":[],\"StyleSheet\":[],\"StyleSheetApplicableStateChangeEventInit\":[],\"StyleSheetChangeEventInit\":[],\"StyleSheetList\":[],\"SubmitEvent\":[\"Event\"],\"SubmitEventInit\":[],\"SubtleCrypto\":[],\"SupportedType\":[],\"SvcOutputMetadata\":[],\"SvgAngle\":[],\"SvgAnimateElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateMotionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateTransformElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimatedAngle\":[],\"SvgAnimatedBoolean\":[],\"SvgAnimatedEnumeration\":[],\"SvgAnimatedInteger\":[],\"SvgAnimatedLength\":[],\"SvgAnimatedLengthList\":[],\"SvgAnimatedNumber\":[],\"SvgAnimatedNumberList\":[],\"SvgAnimatedPreserveAspectRatio\":[],\"SvgAnimatedRect\":[],\"SvgAnimatedString\":[],\"SvgAnimatedTransformList\":[],\"SvgAnimationElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgBoundingBoxOptions\":[],\"SvgCircleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgClipPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgComponentTransferFunctionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgDefsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgDescElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgElement\":[\"Element\",\"EventTarget\",\"Node\"],\"SvgEllipseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgFilterElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgForeignObjectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGeometryElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgGraphicsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgLength\":[],\"SvgLengthList\":[],\"SvgLineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgLinearGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgMarkerElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMaskElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMatrix\":[],\"SvgMetadataElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgNumber\":[],\"SvgNumberList\":[],\"SvgPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPathSeg\":[],\"SvgPathSegArcAbs\":[\"SvgPathSeg\"],\"SvgPathSegArcRel\":[\"SvgPathSeg\"],\"SvgPathSegClosePath\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalRel\":[\"SvgPathSeg\"],\"SvgPathSegList\":[],\"SvgPathSegMovetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegMovetoRel\":[\"SvgPathSeg\"],\"SvgPatternElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgPoint\":[],\"SvgPointList\":[],\"SvgPolygonElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPolylineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPreserveAspectRatio\":[],\"SvgRadialGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgRect\":[],\"SvgRectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgScriptElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgStopElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgStringList\":[],\"SvgStyleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSwitchElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgSymbolElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTextContentElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgTextElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"SvgTextPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTextPositioningElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTitleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTransform\":[],\"SvgTransformList\":[],\"SvgUnitTypes\":[],\"SvgUseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgViewElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgZoomAndPan\":[],\"SvgaElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgfeBlendElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeColorMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeComponentTransferElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeCompositeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeConvolveMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDiffuseLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDisplacementMapElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDistantLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDropShadowElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFloodElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFuncAElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncBElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncGElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncRElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeGaussianBlurElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeNodeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMorphologyElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeOffsetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfePointLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpecularLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpotLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTileElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTurbulenceElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvggElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgmPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgsvgElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgtSpanElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"TaskController\":[\"AbortController\"],\"TaskControllerInit\":[],\"TaskPriority\":[],\"TaskPriorityChangeEvent\":[\"Event\"],\"TaskPriorityChangeEventInit\":[],\"TaskSignal\":[\"AbortSignal\",\"EventTarget\"],\"TaskSignalAnyInit\":[],\"TcpReadyState\":[],\"TcpServerSocket\":[\"EventTarget\"],\"TcpServerSocketEvent\":[\"Event\"],\"TcpServerSocketEventInit\":[],\"TcpSocket\":[\"EventTarget\"],\"TcpSocketBinaryType\":[],\"TcpSocketErrorEvent\":[\"Event\"],\"TcpSocketErrorEventInit\":[],\"TcpSocketEvent\":[\"Event\"],\"TcpSocketEventInit\":[],\"Text\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"TextDecodeOptions\":[],\"TextDecoder\":[],\"TextDecoderOptions\":[],\"TextEncoder\":[],\"TextMetrics\":[],\"TextTrack\":[\"EventTarget\"],\"TextTrackCue\":[\"EventTarget\"],\"TextTrackCueList\":[],\"TextTrackKind\":[],\"TextTrackList\":[\"EventTarget\"],\"TextTrackMode\":[],\"TimeEvent\":[\"Event\"],\"TimeRanges\":[],\"ToggleEvent\":[\"Event\"],\"ToggleEventInit\":[],\"TokenBinding\":[],\"TokenBindingStatus\":[],\"Touch\":[],\"TouchEvent\":[\"Event\",\"UiEvent\"],\"TouchEventInit\":[],\"TouchInit\":[],\"TouchList\":[],\"TrackEvent\":[\"Event\"],\"TrackEventInit\":[],\"TransformStream\":[],\"TransformStreamDefaultController\":[],\"Transformer\":[],\"TransitionEvent\":[\"Event\"],\"TransitionEventInit\":[],\"Transport\":[],\"TreeBoxObject\":[],\"TreeCellInfo\":[],\"TreeView\":[],\"TreeWalker\":[],\"U2f\":[],\"U2fClientData\":[],\"ULongRange\":[],\"UaDataValues\":[],\"UaLowEntropyJson\":[],\"UdpMessageEventInit\":[],\"UdpOptions\":[],\"UiEvent\":[\"Event\"],\"UiEventInit\":[],\"UnderlyingSink\":[],\"UnderlyingSource\":[],\"Url\":[],\"UrlSearchParams\":[],\"Usb\":[\"EventTarget\"],\"UsbAlternateInterface\":[],\"UsbConfiguration\":[],\"UsbConnectionEvent\":[\"Event\"],\"UsbConnectionEventInit\":[],\"UsbControlTransferParameters\":[],\"UsbDevice\":[],\"UsbDeviceFilter\":[],\"UsbDeviceRequestOptions\":[],\"UsbDirection\":[],\"UsbEndpoint\":[],\"UsbEndpointType\":[],\"UsbInTransferResult\":[],\"UsbInterface\":[],\"UsbIsochronousInTransferPacket\":[],\"UsbIsochronousInTransferResult\":[],\"UsbIsochronousOutTransferPacket\":[],\"UsbIsochronousOutTransferResult\":[],\"UsbOutTransferResult\":[],\"UsbPermissionDescriptor\":[],\"UsbPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"UsbPermissionStorage\":[],\"UsbRecipient\":[],\"UsbRequestType\":[],\"UsbTransferStatus\":[],\"UserActivation\":[],\"UserProximityEvent\":[\"Event\"],\"UserProximityEventInit\":[],\"UserVerificationRequirement\":[],\"ValidityState\":[],\"ValueEvent\":[\"Event\"],\"ValueEventInit\":[],\"VideoColorPrimaries\":[],\"VideoColorSpace\":[],\"VideoColorSpaceInit\":[],\"VideoConfiguration\":[],\"VideoDecoder\":[],\"VideoDecoderConfig\":[],\"VideoDecoderInit\":[],\"VideoDecoderSupport\":[],\"VideoEncoder\":[],\"VideoEncoderConfig\":[],\"VideoEncoderEncodeOptions\":[],\"VideoEncoderInit\":[],\"VideoEncoderSupport\":[],\"VideoFacingModeEnum\":[],\"VideoFrame\":[],\"VideoFrameBufferInit\":[],\"VideoFrameCopyToOptions\":[],\"VideoFrameInit\":[],\"VideoMatrixCoefficients\":[],\"VideoPixelFormat\":[],\"VideoPlaybackQuality\":[],\"VideoStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"VideoTrack\":[],\"VideoTrackList\":[\"EventTarget\"],\"VideoTransferCharacteristics\":[],\"ViewTransition\":[],\"VisibilityState\":[],\"VisualViewport\":[\"EventTarget\"],\"VoidCallback\":[],\"VrDisplay\":[\"EventTarget\"],\"VrDisplayCapabilities\":[],\"VrEye\":[],\"VrEyeParameters\":[],\"VrFieldOfView\":[],\"VrFrameData\":[],\"VrLayer\":[],\"VrMockController\":[],\"VrMockDisplay\":[],\"VrPose\":[],\"VrServiceTest\":[],\"VrStageParameters\":[],\"VrSubmitFrameResult\":[],\"VttCue\":[\"EventTarget\",\"TextTrackCue\"],\"VttRegion\":[],\"WakeLock\":[],\"WakeLockSentinel\":[\"EventTarget\"],\"WakeLockType\":[],\"WatchAdvertisementsOptions\":[],\"WaveShaperNode\":[\"AudioNode\",\"EventTarget\"],\"WaveShaperOptions\":[],\"WebGl2RenderingContext\":[],\"WebGlActiveInfo\":[],\"WebGlBuffer\":[],\"WebGlContextAttributes\":[],\"WebGlContextEvent\":[\"Event\"],\"WebGlContextEventInit\":[],\"WebGlFramebuffer\":[],\"WebGlPowerPreference\":[],\"WebGlProgram\":[],\"WebGlQuery\":[],\"WebGlRenderbuffer\":[],\"WebGlRenderingContext\":[],\"WebGlSampler\":[],\"WebGlShader\":[],\"WebGlShaderPrecisionFormat\":[],\"WebGlSync\":[],\"WebGlTexture\":[],\"WebGlTransformFeedback\":[],\"WebGlUniformLocation\":[],\"WebGlVertexArrayObject\":[],\"WebKitCssMatrix\":[\"DomMatrix\",\"DomMatrixReadOnly\"],\"WebSocket\":[\"EventTarget\"],\"WebSocketDict\":[],\"WebSocketElement\":[],\"WebTransport\":[],\"WebTransportBidirectionalStream\":[],\"WebTransportCloseInfo\":[],\"WebTransportCongestionControl\":[],\"WebTransportDatagramDuplexStream\":[],\"WebTransportDatagramStats\":[],\"WebTransportError\":[\"DomException\"],\"WebTransportErrorOptions\":[],\"WebTransportErrorSource\":[],\"WebTransportHash\":[],\"WebTransportOptions\":[],\"WebTransportReceiveStream\":[\"ReadableStream\"],\"WebTransportReceiveStreamStats\":[],\"WebTransportReliabilityMode\":[],\"WebTransportSendStream\":[\"WritableStream\"],\"WebTransportSendStreamOptions\":[],\"WebTransportSendStreamStats\":[],\"WebTransportStats\":[],\"WebglColorBufferFloat\":[],\"WebglCompressedTextureAstc\":[],\"WebglCompressedTextureAtc\":[],\"WebglCompressedTextureEtc\":[],\"WebglCompressedTextureEtc1\":[],\"WebglCompressedTexturePvrtc\":[],\"WebglCompressedTextureS3tc\":[],\"WebglCompressedTextureS3tcSrgb\":[],\"WebglDebugRendererInfo\":[],\"WebglDebugShaders\":[],\"WebglDepthTexture\":[],\"WebglDrawBuffers\":[],\"WebglLoseContext\":[],\"WebglMultiDraw\":[],\"WellKnownDirectory\":[],\"WgslLanguageFeatures\":[],\"WheelEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"WheelEventInit\":[],\"WidevineCdmManifest\":[],\"Window\":[\"EventTarget\"],\"WindowClient\":[\"Client\"],\"Worker\":[\"EventTarget\"],\"WorkerDebuggerGlobalScope\":[\"EventTarget\"],\"WorkerGlobalScope\":[\"EventTarget\"],\"WorkerLocation\":[],\"WorkerNavigator\":[],\"WorkerOptions\":[],\"WorkerType\":[],\"Worklet\":[],\"WorkletGlobalScope\":[],\"WorkletOptions\":[],\"WritableStream\":[],\"WritableStreamDefaultController\":[],\"WritableStreamDefaultWriter\":[],\"WriteCommandType\":[],\"WriteParams\":[],\"XPathExpression\":[],\"XPathNsResolver\":[],\"XPathResult\":[],\"XmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"XmlHttpRequest\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlHttpRequestEventTarget\":[\"EventTarget\"],\"XmlHttpRequestResponseType\":[],\"XmlHttpRequestUpload\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlSerializer\":[],\"XrBoundedReferenceSpace\":[\"EventTarget\",\"XrReferenceSpace\",\"XrSpace\"],\"XrEye\":[],\"XrFrame\":[],\"XrHand\":[],\"XrHandJoint\":[],\"XrHandedness\":[],\"XrInputSource\":[],\"XrInputSourceArray\":[],\"XrInputSourceEvent\":[\"Event\"],\"XrInputSourceEventInit\":[],\"XrInputSourcesChangeEvent\":[\"Event\"],\"XrInputSourcesChangeEventInit\":[],\"XrJointPose\":[\"XrPose\"],\"XrJointSpace\":[\"EventTarget\",\"XrSpace\"],\"XrLayer\":[\"EventTarget\"],\"XrPermissionDescriptor\":[],\"XrPermissionStatus\":[\"EventTarget\",\"PermissionStatus\"],\"XrPose\":[],\"XrReferenceSpace\":[\"EventTarget\",\"XrSpace\"],\"XrReferenceSpaceEvent\":[\"Event\"],\"XrReferenceSpaceEventInit\":[],\"XrReferenceSpaceType\":[],\"XrRenderState\":[],\"XrRenderStateInit\":[],\"XrRigidTransform\":[],\"XrSession\":[\"EventTarget\"],\"XrSessionEvent\":[\"Event\"],\"XrSessionEventInit\":[],\"XrSessionInit\":[],\"XrSessionMode\":[],\"XrSessionSupportedPermissionDescriptor\":[],\"XrSpace\":[\"EventTarget\"],\"XrSystem\":[\"EventTarget\"],\"XrTargetRayMode\":[],\"XrView\":[],\"XrViewerPose\":[\"XrPose\"],\"XrViewport\":[],\"XrVisibilityState\":[],\"XrWebGlLayer\":[\"EventTarget\",\"XrLayer\"],\"XrWebGlLayerInit\":[],\"XsltProcessor\":[],\"console\":[],\"css\":[],\"default\":[\"std\"],\"gpu_buffer_usage\":[],\"gpu_color_write\":[],\"gpu_map_mode\":[],\"gpu_shader_stage\":[],\"gpu_texture_usage\":[],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\"]}}", + "web-sys_0.3.102": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.102\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.125\"}],\"features\":{\"AbortController\":[],\"AbortSignal\":[\"EventTarget\"],\"AbstractRange\":[],\"AddEventListenerOptions\":[],\"AesCbcParams\":[],\"AesCtrParams\":[],\"AesDerivedKeyParams\":[],\"AesGcmParams\":[],\"AesKeyAlgorithm\":[],\"AesKeyGenParams\":[],\"Algorithm\":[],\"AlignSetting\":[],\"AllowedBluetoothDevice\":[],\"AllowedUsbDevice\":[],\"AlphaOption\":[],\"AnalyserNode\":[\"AudioNode\",\"EventTarget\"],\"AnalyserOptions\":[],\"AngleInstancedArrays\":[],\"Animation\":[\"EventTarget\"],\"AnimationEffect\":[],\"AnimationEvent\":[\"Event\"],\"AnimationEventInit\":[],\"AnimationPlayState\":[],\"AnimationPlaybackEvent\":[\"Event\"],\"AnimationPlaybackEventInit\":[],\"AnimationPropertyDetails\":[],\"AnimationPropertyValueDetails\":[],\"AnimationTimeline\":[],\"AssignedNodesOptions\":[],\"AttestationConveyancePreference\":[],\"Attr\":[\"EventTarget\",\"Node\"],\"AttributeNameValue\":[],\"AudioBuffer\":[],\"AudioBufferOptions\":[],\"AudioBufferSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"AudioBufferSourceOptions\":[],\"AudioConfiguration\":[],\"AudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"AudioContextLatencyCategory\":[],\"AudioContextOptions\":[],\"AudioContextState\":[],\"AudioData\":[],\"AudioDataCopyToOptions\":[],\"AudioDataInit\":[],\"AudioDecoder\":[\"EventTarget\"],\"AudioDecoderConfig\":[],\"AudioDecoderInit\":[],\"AudioDecoderSupport\":[],\"AudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"AudioEncoder\":[\"EventTarget\"],\"AudioEncoderConfig\":[],\"AudioEncoderInit\":[],\"AudioEncoderSupport\":[],\"AudioListener\":[],\"AudioNode\":[\"EventTarget\"],\"AudioNodeOptions\":[],\"AudioParam\":[],\"AudioParamMap\":[],\"AudioProcessingEvent\":[\"Event\"],\"AudioSampleFormat\":[],\"AudioScheduledSourceNode\":[\"AudioNode\",\"EventTarget\"],\"AudioSinkInfo\":[],\"AudioSinkOptions\":[],\"AudioSinkType\":[],\"AudioStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"AudioTrack\":[],\"AudioTrackList\":[\"EventTarget\"],\"AudioWorklet\":[\"Worklet\"],\"AudioWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"AudioWorkletNode\":[\"AudioNode\",\"EventTarget\"],\"AudioWorkletNodeOptions\":[],\"AudioWorkletProcessor\":[],\"AuthenticationExtensionsClientInputs\":[],\"AuthenticationExtensionsClientInputsJson\":[],\"AuthenticationExtensionsClientOutputs\":[],\"AuthenticationExtensionsClientOutputsJson\":[],\"AuthenticationExtensionsDevicePublicKeyInputs\":[],\"AuthenticationExtensionsDevicePublicKeyOutputs\":[],\"AuthenticationExtensionsLargeBlobInputs\":[],\"AuthenticationExtensionsLargeBlobOutputs\":[],\"AuthenticationExtensionsPrfInputs\":[],\"AuthenticationExtensionsPrfOutputs\":[],\"AuthenticationExtensionsPrfValues\":[],\"AuthenticationResponseJson\":[],\"AuthenticatorAssertionResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAssertionResponseJson\":[],\"AuthenticatorAttachment\":[],\"AuthenticatorAttestationResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAttestationResponseJson\":[],\"AuthenticatorResponse\":[],\"AuthenticatorSelectionCriteria\":[],\"AuthenticatorTransport\":[],\"AutoKeyword\":[],\"AutocompleteInfo\":[],\"BarProp\":[],\"BaseAudioContext\":[\"EventTarget\"],\"BaseComputedKeyframe\":[],\"BaseKeyframe\":[],\"BasePropertyIndexedKeyframe\":[],\"BasicCardRequest\":[],\"BasicCardResponse\":[],\"BasicCardType\":[],\"BatteryManager\":[\"EventTarget\"],\"BeforeUnloadEvent\":[\"Event\"],\"BinaryType\":[],\"BiquadFilterNode\":[\"AudioNode\",\"EventTarget\"],\"BiquadFilterOptions\":[],\"BiquadFilterType\":[],\"BitrateMode\":[],\"Blob\":[],\"BlobEvent\":[\"Event\"],\"BlobEventInit\":[],\"BlobPropertyBag\":[],\"BlockParsingOptions\":[],\"Bluetooth\":[\"EventTarget\"],\"BluetoothAdvertisingEvent\":[\"Event\"],\"BluetoothAdvertisingEventInit\":[],\"BluetoothCharacteristicProperties\":[],\"BluetoothDataFilterInit\":[],\"BluetoothDevice\":[\"EventTarget\"],\"BluetoothLeScanFilterInit\":[],\"BluetoothManufacturerDataMap\":[],\"BluetoothPermissionDescriptor\":[],\"BluetoothPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"BluetoothPermissionStorage\":[],\"BluetoothRemoteGattCharacteristic\":[\"EventTarget\"],\"BluetoothRemoteGattDescriptor\":[],\"BluetoothRemoteGattServer\":[],\"BluetoothRemoteGattService\":[\"EventTarget\"],\"BluetoothServiceDataMap\":[],\"BluetoothUuid\":[],\"BoxQuadOptions\":[],\"BroadcastChannel\":[\"EventTarget\"],\"BrowserElementDownloadOptions\":[],\"BrowserElementExecuteScriptOptions\":[],\"BrowserFeedWriter\":[],\"BrowserFindCaseSensitivity\":[],\"BrowserFindDirection\":[],\"ByteLengthQueuingStrategy\":[],\"Cache\":[],\"CacheBatchOperation\":[],\"CacheQueryOptions\":[],\"CacheStorage\":[],\"CacheStorageNamespace\":[],\"CanvasCaptureMediaStream\":[\"EventTarget\",\"MediaStream\"],\"CanvasCaptureMediaStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"CanvasGradient\":[],\"CanvasPattern\":[],\"CanvasRenderingContext2d\":[],\"CanvasWindingRule\":[],\"CaretChangedReason\":[],\"CaretPosition\":[],\"CaretStateChangedEventInit\":[],\"CdataSection\":[\"CharacterData\",\"EventTarget\",\"Node\",\"Text\"],\"ChannelCountMode\":[],\"ChannelInterpretation\":[],\"ChannelMergerNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelMergerOptions\":[],\"ChannelSplitterNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelSplitterOptions\":[],\"CharacterData\":[\"EventTarget\",\"Node\"],\"CheckerboardReason\":[],\"CheckerboardReport\":[],\"CheckerboardReportService\":[],\"ChromeFilePropertyBag\":[],\"ChromeWorker\":[\"EventTarget\",\"Worker\"],\"Client\":[],\"ClientQueryOptions\":[],\"ClientRectsAndTexts\":[],\"ClientType\":[],\"Clients\":[],\"Clipboard\":[\"EventTarget\"],\"ClipboardEvent\":[\"Event\"],\"ClipboardEventInit\":[],\"ClipboardItem\":[],\"ClipboardItemOptions\":[],\"ClipboardPermissionDescriptor\":[],\"ClipboardUnsanitizedFormats\":[],\"CloseEvent\":[\"Event\"],\"CloseEventInit\":[],\"CodecState\":[],\"CollectedClientData\":[],\"ColorSpaceConversion\":[],\"CommandEvent\":[\"Event\"],\"CommandEventInit\":[],\"Comment\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"CompositeOperation\":[],\"CompositionEvent\":[\"Event\",\"UiEvent\"],\"CompositionEventInit\":[],\"CompressionFormat\":[],\"CompressionStream\":[],\"ComputedEffectTiming\":[],\"ConnStatusDict\":[],\"ConnectionType\":[],\"ConsoleCounter\":[],\"ConsoleCounterError\":[],\"ConsoleEvent\":[],\"ConsoleInstance\":[],\"ConsoleInstanceOptions\":[],\"ConsoleLevel\":[],\"ConsoleLogLevel\":[],\"ConsoleProfileEvent\":[],\"ConsoleStackEntry\":[],\"ConsoleTimerError\":[],\"ConsoleTimerLogOrEnd\":[],\"ConsoleTimerStart\":[],\"ConstantSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"ConstantSourceOptions\":[],\"ConstrainBooleanParameters\":[],\"ConstrainDomStringParameters\":[],\"ConstrainDoubleRange\":[],\"ConstrainLongRange\":[],\"ContextAttributes2d\":[],\"ConvertCoordinateOptions\":[],\"ConvolverNode\":[\"AudioNode\",\"EventTarget\"],\"ConvolverOptions\":[],\"CookieChangeEvent\":[\"Event\"],\"CookieChangeEventInit\":[],\"CookieInit\":[],\"CookieListItem\":[],\"CookieSameSite\":[],\"CookieStore\":[\"EventTarget\"],\"CookieStoreDeleteOptions\":[],\"CookieStoreGetOptions\":[],\"CookieStoreManager\":[],\"Coordinates\":[],\"CountQueuingStrategy\":[],\"Credential\":[],\"CredentialCreationOptions\":[],\"CredentialPropertiesOutput\":[],\"CredentialRequestOptions\":[],\"CredentialsContainer\":[],\"Crypto\":[],\"CryptoKey\":[],\"CryptoKeyPair\":[],\"CssAnimation\":[\"Animation\",\"EventTarget\"],\"CssBoxType\":[],\"CssConditionRule\":[\"CssGroupingRule\",\"CssRule\"],\"CssCounterStyleRule\":[\"CssRule\"],\"CssFontFaceRule\":[\"CssRule\"],\"CssFontFeatureValuesRule\":[\"CssRule\"],\"CssGroupingRule\":[\"CssRule\"],\"CssImportRule\":[\"CssRule\"],\"CssKeyframeRule\":[\"CssRule\"],\"CssKeyframesRule\":[\"CssRule\"],\"CssMediaRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssNamespaceRule\":[\"CssRule\"],\"CssPageRule\":[\"CssRule\"],\"CssPseudoElement\":[],\"CssRule\":[],\"CssRuleList\":[],\"CssStyleDeclaration\":[],\"CssStyleRule\":[\"CssRule\"],\"CssStyleSheet\":[\"StyleSheet\"],\"CssStyleSheetParsingMode\":[],\"CssSupportsRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssTransition\":[\"Animation\",\"EventTarget\"],\"CssViewTransitionRule\":[\"CssRule\"],\"CustomElementRegistry\":[],\"CustomEvent\":[\"Event\"],\"CustomEventInit\":[],\"DataTransfer\":[],\"DataTransferItem\":[],\"DataTransferItemList\":[],\"DateTimeValue\":[],\"DecoderDoctorNotification\":[],\"DecoderDoctorNotificationType\":[],\"DecompressionStream\":[],\"DedicatedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"DelayNode\":[\"AudioNode\",\"EventTarget\"],\"DelayOptions\":[],\"DeviceAcceleration\":[],\"DeviceAccelerationInit\":[],\"DeviceLightEvent\":[\"Event\"],\"DeviceLightEventInit\":[],\"DeviceMotionEvent\":[\"Event\"],\"DeviceMotionEventInit\":[],\"DeviceOrientationEvent\":[\"Event\"],\"DeviceOrientationEventInit\":[],\"DeviceProximityEvent\":[\"Event\"],\"DeviceProximityEventInit\":[],\"DeviceRotationRate\":[],\"DeviceRotationRateInit\":[],\"DhKeyDeriveParams\":[],\"DirectionSetting\":[],\"Directory\":[],\"DirectoryPickerOptions\":[],\"DisplayMediaStreamConstraints\":[],\"DisplayNameOptions\":[],\"DisplayNameResult\":[],\"DistanceModelType\":[],\"DnsCacheDict\":[],\"DnsCacheEntry\":[],\"DnsLookupDict\":[],\"Document\":[\"EventTarget\",\"Node\"],\"DocumentFragment\":[\"EventTarget\",\"Node\"],\"DocumentTimeline\":[\"AnimationTimeline\"],\"DocumentTimelineOptions\":[],\"DocumentType\":[\"EventTarget\",\"Node\"],\"DomError\":[],\"DomException\":[],\"DomImplementation\":[],\"DomMatrix\":[\"DomMatrixReadOnly\"],\"DomMatrix2dInit\":[],\"DomMatrixInit\":[],\"DomMatrixReadOnly\":[],\"DomParser\":[],\"DomPoint\":[\"DomPointReadOnly\"],\"DomPointInit\":[],\"DomPointReadOnly\":[],\"DomQuad\":[],\"DomQuadInit\":[],\"DomQuadJson\":[],\"DomRect\":[\"DomRectReadOnly\"],\"DomRectInit\":[],\"DomRectList\":[],\"DomRectReadOnly\":[],\"DomRequest\":[\"EventTarget\"],\"DomRequestReadyState\":[],\"DomStringList\":[],\"DomStringMap\":[],\"DomTokenList\":[],\"DomWindowResizeEventDetail\":[],\"DoubleRange\":[],\"DragEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"DragEventInit\":[],\"DynamicsCompressorNode\":[\"AudioNode\",\"EventTarget\"],\"DynamicsCompressorOptions\":[],\"EcKeyAlgorithm\":[],\"EcKeyGenParams\":[],\"EcKeyImportParams\":[],\"EcdhKeyDeriveParams\":[],\"EcdsaParams\":[],\"EffectTiming\":[],\"Element\":[\"EventTarget\",\"Node\"],\"ElementCreationOptions\":[],\"ElementDefinitionOptions\":[],\"EncodedAudioChunk\":[],\"EncodedAudioChunkInit\":[],\"EncodedAudioChunkMetadata\":[],\"EncodedAudioChunkType\":[],\"EncodedVideoChunk\":[],\"EncodedVideoChunkInit\":[],\"EncodedVideoChunkMetadata\":[],\"EncodedVideoChunkType\":[],\"EndingTypes\":[],\"ErrorCallback\":[],\"ErrorEvent\":[\"Event\"],\"ErrorEventInit\":[],\"Event\":[],\"EventInit\":[],\"EventListener\":[],\"EventListenerOptions\":[],\"EventModifierInit\":[],\"EventSource\":[\"EventTarget\"],\"EventSourceInit\":[],\"EventTarget\":[],\"Exception\":[],\"ExtBlendMinmax\":[],\"ExtColorBufferFloat\":[],\"ExtColorBufferHalfFloat\":[],\"ExtDisjointTimerQuery\":[],\"ExtFragDepth\":[],\"ExtSRgb\":[],\"ExtShaderTextureLod\":[],\"ExtTextureFilterAnisotropic\":[],\"ExtTextureNorm16\":[],\"ExtendableCookieChangeEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableCookieChangeEventInit\":[],\"ExtendableEvent\":[\"Event\"],\"ExtendableEventInit\":[],\"ExtendableMessageEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableMessageEventInit\":[],\"External\":[],\"FakePluginMimeEntry\":[],\"FakePluginTagInit\":[],\"FetchEvent\":[\"Event\",\"ExtendableEvent\"],\"FetchEventInit\":[],\"FetchObserver\":[\"EventTarget\"],\"FetchReadableStreamReadDataArray\":[],\"FetchReadableStreamReadDataDone\":[],\"FetchState\":[],\"File\":[\"Blob\"],\"FileCallback\":[],\"FileList\":[],\"FilePickerAcceptType\":[],\"FilePickerOptions\":[],\"FilePropertyBag\":[],\"FileReader\":[\"EventTarget\"],\"FileReaderSync\":[],\"FileSystem\":[],\"FileSystemCreateWritableOptions\":[],\"FileSystemDirectoryEntry\":[\"FileSystemEntry\"],\"FileSystemDirectoryHandle\":[\"FileSystemHandle\"],\"FileSystemDirectoryReader\":[],\"FileSystemEntriesCallback\":[],\"FileSystemEntry\":[],\"FileSystemEntryCallback\":[],\"FileSystemFileEntry\":[\"FileSystemEntry\"],\"FileSystemFileHandle\":[\"FileSystemHandle\"],\"FileSystemFlags\":[],\"FileSystemGetDirectoryOptions\":[],\"FileSystemGetFileOptions\":[],\"FileSystemHandle\":[],\"FileSystemHandleKind\":[],\"FileSystemHandlePermissionDescriptor\":[],\"FileSystemPermissionDescriptor\":[],\"FileSystemPermissionMode\":[],\"FileSystemReadWriteOptions\":[],\"FileSystemRemoveOptions\":[],\"FileSystemSyncAccessHandle\":[],\"FileSystemSyncAccessHandleMode\":[],\"FileSystemSyncAccessHandleOptions\":[],\"FileSystemWritableFileStream\":[\"WritableStream\"],\"FillLightMode\":[],\"FillMode\":[],\"FlashClassification\":[],\"FlowControlType\":[],\"FocusEvent\":[\"Event\",\"UiEvent\"],\"FocusEventInit\":[],\"FocusOptions\":[],\"FontData\":[],\"FontFace\":[],\"FontFaceDescriptors\":[],\"FontFaceLoadStatus\":[],\"FontFaceSet\":[\"EventTarget\"],\"FontFaceSetIterator\":[],\"FontFaceSetIteratorResult\":[],\"FontFaceSetLoadEvent\":[\"Event\"],\"FontFaceSetLoadEventInit\":[],\"FontFaceSetLoadStatus\":[],\"FormData\":[],\"FrameType\":[],\"FuzzingFunctions\":[],\"GainNode\":[\"AudioNode\",\"EventTarget\"],\"GainOptions\":[],\"Gamepad\":[],\"GamepadButton\":[],\"GamepadEffectParameters\":[],\"GamepadEvent\":[\"Event\"],\"GamepadEventInit\":[],\"GamepadHand\":[],\"GamepadHapticActuator\":[],\"GamepadHapticActuatorType\":[],\"GamepadHapticEffectType\":[],\"GamepadHapticsResult\":[],\"GamepadMappingType\":[],\"GamepadPose\":[],\"GamepadTouch\":[],\"Geolocation\":[],\"GeolocationCoordinates\":[],\"GeolocationPosition\":[],\"GeolocationPositionError\":[],\"GestureEvent\":[\"Event\",\"UiEvent\"],\"GetAnimationsOptions\":[],\"GetRootNodeOptions\":[],\"GetUserMediaRequest\":[],\"Gpu\":[],\"GpuAdapter\":[],\"GpuAdapterInfo\":[],\"GpuAddressMode\":[],\"GpuAutoLayoutMode\":[],\"GpuBindGroup\":[],\"GpuBindGroupDescriptor\":[],\"GpuBindGroupEntry\":[],\"GpuBindGroupLayout\":[],\"GpuBindGroupLayoutDescriptor\":[],\"GpuBindGroupLayoutEntry\":[],\"GpuBlendComponent\":[],\"GpuBlendFactor\":[],\"GpuBlendOperation\":[],\"GpuBlendState\":[],\"GpuBuffer\":[],\"GpuBufferBinding\":[],\"GpuBufferBindingLayout\":[],\"GpuBufferBindingType\":[],\"GpuBufferDescriptor\":[],\"GpuBufferMapState\":[],\"GpuCanvasAlphaMode\":[],\"GpuCanvasConfiguration\":[],\"GpuCanvasContext\":[],\"GpuCanvasToneMapping\":[],\"GpuCanvasToneMappingMode\":[],\"GpuColorDict\":[],\"GpuColorTargetState\":[],\"GpuCommandBuffer\":[],\"GpuCommandBufferDescriptor\":[],\"GpuCommandEncoder\":[],\"GpuCommandEncoderDescriptor\":[],\"GpuCompareFunction\":[],\"GpuCompilationInfo\":[],\"GpuCompilationMessage\":[],\"GpuCompilationMessageType\":[],\"GpuComputePassDescriptor\":[],\"GpuComputePassEncoder\":[],\"GpuComputePassTimestampWrites\":[],\"GpuComputePipeline\":[],\"GpuComputePipelineDescriptor\":[],\"GpuCopyExternalImageDestInfo\":[],\"GpuCopyExternalImageSourceInfo\":[],\"GpuCullMode\":[],\"GpuDepthStencilState\":[],\"GpuDevice\":[\"EventTarget\"],\"GpuDeviceDescriptor\":[],\"GpuDeviceLostInfo\":[],\"GpuDeviceLostReason\":[],\"GpuError\":[],\"GpuErrorFilter\":[],\"GpuExtent3dDict\":[],\"GpuExternalTexture\":[],\"GpuExternalTextureBindingLayout\":[],\"GpuExternalTextureDescriptor\":[],\"GpuFeatureName\":[],\"GpuFilterMode\":[],\"GpuFragmentState\":[],\"GpuFrontFace\":[],\"GpuIndexFormat\":[],\"GpuInternalError\":[\"GpuError\"],\"GpuLoadOp\":[],\"GpuMipmapFilterMode\":[],\"GpuMultisampleState\":[],\"GpuObjectDescriptorBase\":[],\"GpuOrigin2dDict\":[],\"GpuOrigin3dDict\":[],\"GpuOutOfMemoryError\":[\"GpuError\"],\"GpuPipelineDescriptorBase\":[],\"GpuPipelineError\":[\"DomException\"],\"GpuPipelineErrorInit\":[],\"GpuPipelineErrorReason\":[],\"GpuPipelineLayout\":[],\"GpuPipelineLayoutDescriptor\":[],\"GpuPowerPreference\":[],\"GpuPrimitiveState\":[],\"GpuPrimitiveTopology\":[],\"GpuProgrammableStage\":[],\"GpuQuerySet\":[],\"GpuQuerySetDescriptor\":[],\"GpuQueryType\":[],\"GpuQueue\":[],\"GpuQueueDescriptor\":[],\"GpuRenderBundle\":[],\"GpuRenderBundleDescriptor\":[],\"GpuRenderBundleEncoder\":[],\"GpuRenderBundleEncoderDescriptor\":[],\"GpuRenderPassColorAttachment\":[],\"GpuRenderPassDepthStencilAttachment\":[],\"GpuRenderPassDescriptor\":[],\"GpuRenderPassEncoder\":[],\"GpuRenderPassLayout\":[],\"GpuRenderPassTimestampWrites\":[],\"GpuRenderPipeline\":[],\"GpuRenderPipelineDescriptor\":[],\"GpuRequestAdapterOptions\":[],\"GpuSampler\":[],\"GpuSamplerBindingLayout\":[],\"GpuSamplerBindingType\":[],\"GpuSamplerDescriptor\":[],\"GpuShaderModule\":[],\"GpuShaderModuleCompilationHint\":[],\"GpuShaderModuleDescriptor\":[],\"GpuStencilFaceState\":[],\"GpuStencilOperation\":[],\"GpuStorageTextureAccess\":[],\"GpuStorageTextureBindingLayout\":[],\"GpuStoreOp\":[],\"GpuSupportedFeatures\":[],\"GpuSupportedLimits\":[],\"GpuTexelCopyBufferInfo\":[],\"GpuTexelCopyBufferLayout\":[],\"GpuTexelCopyTextureInfo\":[],\"GpuTexture\":[],\"GpuTextureAspect\":[],\"GpuTextureBindingLayout\":[],\"GpuTextureDescriptor\":[],\"GpuTextureDimension\":[],\"GpuTextureFormat\":[],\"GpuTextureSampleType\":[],\"GpuTextureView\":[],\"GpuTextureViewDescriptor\":[],\"GpuTextureViewDimension\":[],\"GpuUncapturedErrorEvent\":[\"Event\"],\"GpuUncapturedErrorEventInit\":[],\"GpuValidationError\":[\"GpuError\"],\"GpuVertexAttribute\":[],\"GpuVertexBufferLayout\":[],\"GpuVertexFormat\":[],\"GpuVertexState\":[],\"GpuVertexStepMode\":[],\"GroupedHistoryEventInit\":[],\"HalfOpenInfoDict\":[],\"HardwareAcceleration\":[],\"HashChangeEvent\":[\"Event\"],\"HashChangeEventInit\":[],\"Headers\":[],\"HeadersGuardEnum\":[],\"Hid\":[\"EventTarget\"],\"HidCollectionInfo\":[],\"HidConnectionEvent\":[\"Event\"],\"HidConnectionEventInit\":[],\"HidDevice\":[\"EventTarget\"],\"HidDeviceFilter\":[],\"HidDeviceRequestOptions\":[],\"HidInputReportEvent\":[\"Event\"],\"HidInputReportEventInit\":[],\"HidReportInfo\":[],\"HidReportItem\":[],\"HidUnitSystem\":[],\"HiddenPluginEventInit\":[],\"Highlight\":[],\"HighlightHitResult\":[],\"HighlightRegistry\":[],\"HighlightType\":[],\"HighlightsFromPointOptions\":[],\"History\":[],\"HitRegionOptions\":[],\"HkdfParams\":[],\"HmacDerivedKeyParams\":[],\"HmacImportParams\":[],\"HmacKeyAlgorithm\":[],\"HmacKeyGenParams\":[],\"HtmlAllCollection\":[],\"HtmlAnchorElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAudioElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HtmlBaseElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBodyElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlButtonElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCanvasElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCollection\":[],\"HtmlDListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDetailsElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDialogElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDirectoryElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDivElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"HtmlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"HtmlEmbedElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFieldSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFontElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFormControlsCollection\":[\"HtmlCollection\"],\"HtmlFormElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadingElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHtmlElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlIFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlImageElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlInputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLabelElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLegendElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLiElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLinkElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMapElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMediaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuItemElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMetaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMeterElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlModElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlObjectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptGroupElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionsCollection\":[\"HtmlCollection\"],\"HtmlOutputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParagraphElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParamElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPictureElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPreElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlProgressElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlQuoteElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlScriptElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSelectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSlotElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSourceElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSpanElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlStyleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCaptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCellElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableColElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableRowElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableSectionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTemplateElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTextAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTimeElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTitleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTrackElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUnknownElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlVideoElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HttpConnDict\":[],\"HttpConnInfo\":[],\"HttpConnectionElement\":[],\"IdbCursor\":[],\"IdbCursorDirection\":[],\"IdbCursorWithValue\":[\"IdbCursor\"],\"IdbDatabase\":[\"EventTarget\"],\"IdbFactory\":[],\"IdbFileHandle\":[\"EventTarget\"],\"IdbFileMetadataParameters\":[],\"IdbFileRequest\":[\"DomRequest\",\"EventTarget\"],\"IdbIndex\":[],\"IdbIndexParameters\":[],\"IdbKeyRange\":[],\"IdbLocaleAwareKeyRange\":[\"IdbKeyRange\"],\"IdbMutableFile\":[\"EventTarget\"],\"IdbObjectStore\":[],\"IdbObjectStoreParameters\":[],\"IdbOpenDbOptions\":[],\"IdbOpenDbRequest\":[\"EventTarget\",\"IdbRequest\"],\"IdbRequest\":[\"EventTarget\"],\"IdbRequestReadyState\":[],\"IdbTransaction\":[\"EventTarget\"],\"IdbTransactionDurability\":[],\"IdbTransactionMode\":[],\"IdbTransactionOptions\":[],\"IdbVersionChangeEvent\":[\"Event\"],\"IdbVersionChangeEventInit\":[],\"IdleDeadline\":[],\"IdleRequestOptions\":[],\"IirFilterNode\":[\"AudioNode\",\"EventTarget\"],\"IirFilterOptions\":[],\"ImageBitmap\":[],\"ImageBitmapOptions\":[],\"ImageBitmapRenderingContext\":[],\"ImageCapture\":[],\"ImageCaptureError\":[],\"ImageCaptureErrorEvent\":[\"Event\"],\"ImageCaptureErrorEventInit\":[],\"ImageData\":[],\"ImageDecodeOptions\":[],\"ImageDecodeResult\":[],\"ImageDecoder\":[],\"ImageDecoderInit\":[],\"ImageEncodeOptions\":[],\"ImageOrientation\":[],\"ImageTrack\":[],\"ImageTrackList\":[],\"InputDeviceInfo\":[\"MediaDeviceInfo\"],\"InputEvent\":[\"Event\",\"UiEvent\"],\"InputEventInit\":[],\"IntersectionObserver\":[],\"IntersectionObserverEntry\":[],\"IntersectionObserverEntryInit\":[],\"IntersectionObserverInit\":[],\"IntlUtils\":[],\"IsInputPendingOptions\":[],\"IterableKeyAndValueResult\":[],\"IterableKeyOrValueResult\":[],\"IterationCompositeOperation\":[],\"JsonWebKey\":[],\"KeyAlgorithm\":[],\"KeyEvent\":[],\"KeyFrameRequestEvent\":[\"Event\"],\"KeyIdsInitData\":[],\"KeyboardEvent\":[\"Event\",\"UiEvent\"],\"KeyboardEventInit\":[],\"KeyframeAnimationOptions\":[],\"KeyframeEffect\":[\"AnimationEffect\"],\"KeyframeEffectOptions\":[],\"L10nElement\":[],\"L10nValue\":[],\"LargeBlobSupport\":[],\"LatencyMode\":[],\"LifecycleCallbacks\":[],\"LineAlignSetting\":[],\"ListBoxObject\":[],\"LocalMediaStream\":[\"EventTarget\",\"MediaStream\"],\"LocaleInfo\":[],\"Location\":[],\"Lock\":[],\"LockInfo\":[],\"LockManager\":[],\"LockManagerSnapshot\":[],\"LockMode\":[],\"LockOptions\":[],\"MathMlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"MediaCapabilities\":[],\"MediaCapabilitiesInfo\":[],\"MediaConfiguration\":[],\"MediaDecodingConfiguration\":[],\"MediaDecodingType\":[],\"MediaDeviceInfo\":[],\"MediaDeviceKind\":[],\"MediaDevices\":[\"EventTarget\"],\"MediaElementAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaElementAudioSourceOptions\":[],\"MediaEncodingConfiguration\":[],\"MediaEncodingType\":[],\"MediaEncryptedEvent\":[\"Event\"],\"MediaError\":[],\"MediaImage\":[],\"MediaKeyError\":[\"Event\"],\"MediaKeyMessageEvent\":[\"Event\"],\"MediaKeyMessageEventInit\":[],\"MediaKeyMessageType\":[],\"MediaKeyNeededEventInit\":[],\"MediaKeySession\":[\"EventTarget\"],\"MediaKeySessionType\":[],\"MediaKeyStatus\":[],\"MediaKeyStatusMap\":[],\"MediaKeySystemAccess\":[],\"MediaKeySystemConfiguration\":[],\"MediaKeySystemMediaCapability\":[],\"MediaKeySystemStatus\":[],\"MediaKeys\":[],\"MediaKeysPolicy\":[],\"MediaKeysRequirement\":[],\"MediaList\":[],\"MediaMetadata\":[],\"MediaMetadataInit\":[],\"MediaPositionState\":[],\"MediaQueryList\":[\"EventTarget\"],\"MediaQueryListEvent\":[\"Event\"],\"MediaQueryListEventInit\":[],\"MediaRecorder\":[\"EventTarget\"],\"MediaRecorderErrorEvent\":[\"Event\"],\"MediaRecorderErrorEventInit\":[],\"MediaRecorderOptions\":[],\"MediaSession\":[],\"MediaSessionAction\":[],\"MediaSessionActionDetails\":[],\"MediaSessionPlaybackState\":[],\"MediaSettingsRange\":[],\"MediaSource\":[\"EventTarget\"],\"MediaSourceEndOfStreamError\":[],\"MediaSourceEnum\":[],\"MediaSourceReadyState\":[],\"MediaStream\":[\"EventTarget\"],\"MediaStreamAudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceOptions\":[],\"MediaStreamConstraints\":[],\"MediaStreamError\":[],\"MediaStreamEvent\":[\"Event\"],\"MediaStreamEventInit\":[],\"MediaStreamTrack\":[\"EventTarget\"],\"MediaStreamTrackEvent\":[\"Event\"],\"MediaStreamTrackEventInit\":[],\"MediaStreamTrackGenerator\":[\"EventTarget\",\"MediaStreamTrack\"],\"MediaStreamTrackGeneratorInit\":[],\"MediaStreamTrackProcessor\":[],\"MediaStreamTrackProcessorInit\":[],\"MediaStreamTrackState\":[],\"MediaTrackCapabilities\":[],\"MediaTrackConstraintSet\":[],\"MediaTrackConstraints\":[],\"MediaTrackSettings\":[],\"MediaTrackSupportedConstraints\":[],\"MemoryAttribution\":[],\"MemoryAttributionContainer\":[],\"MemoryBreakdownEntry\":[],\"MemoryMeasurement\":[],\"MessageChannel\":[],\"MessageEvent\":[\"Event\"],\"MessageEventInit\":[],\"MessagePort\":[\"EventTarget\"],\"MeteringMode\":[],\"MidiAccess\":[\"EventTarget\"],\"MidiConnectionEvent\":[\"Event\"],\"MidiConnectionEventInit\":[],\"MidiInput\":[\"EventTarget\",\"MidiPort\"],\"MidiInputMap\":[],\"MidiMessageEvent\":[\"Event\"],\"MidiMessageEventInit\":[],\"MidiOptions\":[],\"MidiOutput\":[\"EventTarget\",\"MidiPort\"],\"MidiOutputMap\":[],\"MidiPort\":[\"EventTarget\"],\"MidiPortConnectionState\":[],\"MidiPortDeviceState\":[],\"MidiPortType\":[],\"MimeType\":[],\"MimeTypeArray\":[],\"MouseEvent\":[\"Event\",\"UiEvent\"],\"MouseEventInit\":[],\"MouseScrollEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"MozDebug\":[],\"MutationEvent\":[\"Event\"],\"MutationObserver\":[],\"MutationObserverInit\":[],\"MutationObservingInfo\":[],\"MutationRecord\":[],\"NamedNodeMap\":[],\"NativeOsFileReadOptions\":[],\"NativeOsFileWriteAtomicOptions\":[],\"NavigationType\":[],\"Navigator\":[],\"NavigatorAutomationInformation\":[],\"NavigatorUaBrandVersion\":[],\"NavigatorUaData\":[],\"NetworkCommandOptions\":[],\"NetworkInformation\":[\"EventTarget\"],\"NetworkResultOptions\":[],\"Node\":[\"EventTarget\"],\"NodeFilter\":[],\"NodeIterator\":[],\"NodeList\":[],\"Notification\":[\"EventTarget\"],\"NotificationAction\":[],\"NotificationDirection\":[],\"NotificationEvent\":[\"Event\",\"ExtendableEvent\"],\"NotificationEventInit\":[],\"NotificationOptions\":[],\"NotificationPermission\":[],\"ObserverCallback\":[],\"OesElementIndexUint\":[],\"OesStandardDerivatives\":[],\"OesTextureFloat\":[],\"OesTextureFloatLinear\":[],\"OesTextureHalfFloat\":[],\"OesTextureHalfFloatLinear\":[],\"OesVertexArrayObject\":[],\"OfflineAudioCompletionEvent\":[\"Event\"],\"OfflineAudioCompletionEventInit\":[],\"OfflineAudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"OfflineAudioContextOptions\":[],\"OfflineResourceList\":[\"EventTarget\"],\"OffscreenCanvas\":[\"EventTarget\"],\"OffscreenCanvasRenderingContext2d\":[],\"OpenFilePickerOptions\":[],\"OpenWindowEventDetail\":[],\"OptionalEffectTiming\":[],\"OrientationLockType\":[],\"OrientationType\":[],\"OscillatorNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"OscillatorOptions\":[],\"OscillatorType\":[],\"OverSampleType\":[],\"OvrMultiview2\":[],\"PageTransitionEvent\":[\"Event\"],\"PageTransitionEventInit\":[],\"PaintRequest\":[],\"PaintRequestList\":[],\"PaintWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"PannerNode\":[\"AudioNode\",\"EventTarget\"],\"PannerOptions\":[],\"PanningModelType\":[],\"ParityType\":[],\"Path2d\":[],\"PaymentAddress\":[],\"PaymentComplete\":[],\"PaymentMethodChangeEvent\":[\"Event\",\"PaymentRequestUpdateEvent\"],\"PaymentMethodChangeEventInit\":[],\"PaymentRequestUpdateEvent\":[\"Event\"],\"PaymentRequestUpdateEventInit\":[],\"PaymentResponse\":[],\"Pbkdf2Params\":[],\"PcImplIceConnectionState\":[],\"PcImplIceGatheringState\":[],\"PcImplSignalingState\":[],\"PcObserverStateType\":[],\"Performance\":[\"EventTarget\"],\"PerformanceEntry\":[],\"PerformanceEntryEventInit\":[],\"PerformanceEntryFilterOptions\":[],\"PerformanceMark\":[\"PerformanceEntry\"],\"PerformanceMarkOptions\":[],\"PerformanceMeasure\":[\"PerformanceEntry\"],\"PerformanceMeasureOptions\":[],\"PerformanceNavigation\":[],\"PerformanceNavigationTiming\":[\"PerformanceEntry\",\"PerformanceResourceTiming\"],\"PerformanceObserver\":[],\"PerformanceObserverEntryList\":[],\"PerformanceObserverInit\":[],\"PerformanceResourceTiming\":[\"PerformanceEntry\"],\"PerformanceServerTiming\":[],\"PerformanceTiming\":[],\"PeriodicWave\":[],\"PeriodicWaveConstraints\":[],\"PeriodicWaveOptions\":[],\"PermissionDescriptor\":[],\"PermissionName\":[],\"PermissionState\":[],\"PermissionStatus\":[\"EventTarget\"],\"Permissions\":[],\"PhotoCapabilities\":[],\"PhotoSettings\":[],\"PictureInPictureEvent\":[\"Event\"],\"PictureInPictureEventInit\":[],\"PictureInPictureWindow\":[\"EventTarget\"],\"PlaneLayout\":[],\"PlaybackDirection\":[],\"Plugin\":[],\"PluginArray\":[],\"PluginCrashedEventInit\":[],\"Point2d\":[],\"PointerEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"PointerEventInit\":[],\"PopStateEvent\":[\"Event\"],\"PopStateEventInit\":[],\"PopupBlockedEvent\":[\"Event\"],\"PopupBlockedEventInit\":[],\"Position\":[],\"PositionAlignSetting\":[],\"PositionError\":[],\"PositionOptions\":[],\"PremultiplyAlpha\":[],\"Presentation\":[],\"PresentationAvailability\":[\"EventTarget\"],\"PresentationConnection\":[\"EventTarget\"],\"PresentationConnectionAvailableEvent\":[\"Event\"],\"PresentationConnectionAvailableEventInit\":[],\"PresentationConnectionBinaryType\":[],\"PresentationConnectionCloseEvent\":[\"Event\"],\"PresentationConnectionCloseEventInit\":[],\"PresentationConnectionClosedReason\":[],\"PresentationConnectionList\":[\"EventTarget\"],\"PresentationConnectionState\":[],\"PresentationReceiver\":[],\"PresentationRequest\":[\"EventTarget\"],\"PresentationStyle\":[],\"ProcessingInstruction\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"ProfileTimelineLayerRect\":[],\"ProfileTimelineMarker\":[],\"ProfileTimelineMessagePortOperationType\":[],\"ProfileTimelineStackFrame\":[],\"ProfileTimelineWorkerOperationType\":[],\"ProgressEvent\":[\"Event\"],\"ProgressEventInit\":[],\"PromiseNativeHandler\":[],\"PromiseRejectionEvent\":[\"Event\"],\"PromiseRejectionEventInit\":[],\"PublicKeyCredential\":[\"Credential\"],\"PublicKeyCredentialCreationOptions\":[],\"PublicKeyCredentialCreationOptionsJson\":[],\"PublicKeyCredentialDescriptor\":[],\"PublicKeyCredentialDescriptorJson\":[],\"PublicKeyCredentialEntity\":[],\"PublicKeyCredentialHints\":[],\"PublicKeyCredentialParameters\":[],\"PublicKeyCredentialRequestOptions\":[],\"PublicKeyCredentialRequestOptionsJson\":[],\"PublicKeyCredentialRpEntity\":[],\"PublicKeyCredentialType\":[],\"PublicKeyCredentialUserEntity\":[],\"PublicKeyCredentialUserEntityJson\":[],\"PushEncryptionKeyName\":[],\"PushEvent\":[\"Event\",\"ExtendableEvent\"],\"PushEventInit\":[],\"PushManager\":[],\"PushMessageData\":[],\"PushPermissionState\":[],\"PushSubscription\":[],\"PushSubscriptionInit\":[],\"PushSubscriptionJson\":[],\"PushSubscriptionKeys\":[],\"PushSubscriptionOptions\":[],\"PushSubscriptionOptionsInit\":[],\"QueryOptions\":[],\"QueuingStrategy\":[],\"QueuingStrategyInit\":[],\"RadioNodeList\":[\"NodeList\"],\"Range\":[\"AbstractRange\"],\"RcwnPerfStats\":[],\"RcwnStatus\":[],\"ReadableByteStreamController\":[],\"ReadableStream\":[],\"ReadableStreamByobReader\":[],\"ReadableStreamByobRequest\":[],\"ReadableStreamDefaultController\":[],\"ReadableStreamDefaultReader\":[],\"ReadableStreamGetReaderOptions\":[],\"ReadableStreamIteratorOptions\":[],\"ReadableStreamReadResult\":[],\"ReadableStreamReaderMode\":[],\"ReadableStreamType\":[],\"ReadableWritablePair\":[],\"RecordingState\":[],\"RedEyeReduction\":[],\"ReferrerPolicy\":[],\"RegisterRequest\":[],\"RegisterResponse\":[],\"RegisteredKey\":[],\"RegistrationOptions\":[],\"RegistrationResponseJson\":[],\"Request\":[],\"RequestCache\":[],\"RequestCredentials\":[],\"RequestDestination\":[],\"RequestDeviceOptions\":[],\"RequestInit\":[],\"RequestMediaKeySystemAccessNotification\":[],\"RequestMode\":[],\"RequestRedirect\":[],\"ResidentKeyRequirement\":[],\"ResizeObserver\":[],\"ResizeObserverBoxOptions\":[],\"ResizeObserverEntry\":[],\"ResizeObserverOptions\":[],\"ResizeObserverSize\":[],\"ResizeQuality\":[],\"Response\":[],\"ResponseInit\":[],\"ResponseType\":[],\"RsaHashedImportParams\":[],\"RsaOaepParams\":[],\"RsaOtherPrimesInfo\":[],\"RsaPssParams\":[],\"RtcAnswerOptions\":[],\"RtcBundlePolicy\":[],\"RtcCertificate\":[],\"RtcCertificateExpiration\":[],\"RtcCodecStats\":[],\"RtcConfiguration\":[],\"RtcDataChannel\":[\"EventTarget\"],\"RtcDataChannelEvent\":[\"Event\"],\"RtcDataChannelEventInit\":[],\"RtcDataChannelInit\":[],\"RtcDataChannelState\":[],\"RtcDataChannelType\":[],\"RtcDegradationPreference\":[],\"RtcEncodedAudioFrame\":[],\"RtcEncodedAudioFrameMetadata\":[],\"RtcEncodedAudioFrameOptions\":[],\"RtcEncodedVideoFrame\":[],\"RtcEncodedVideoFrameMetadata\":[],\"RtcEncodedVideoFrameOptions\":[],\"RtcEncodedVideoFrameType\":[],\"RtcFecParameters\":[],\"RtcIceCandidate\":[],\"RtcIceCandidateInit\":[],\"RtcIceCandidatePairStats\":[],\"RtcIceCandidateStats\":[],\"RtcIceComponentStats\":[],\"RtcIceConnectionState\":[],\"RtcIceCredentialType\":[],\"RtcIceGatheringState\":[],\"RtcIceServer\":[],\"RtcIceTransportPolicy\":[],\"RtcIdentityAssertion\":[],\"RtcIdentityAssertionResult\":[],\"RtcIdentityProvider\":[],\"RtcIdentityProviderDetails\":[],\"RtcIdentityProviderOptions\":[],\"RtcIdentityProviderRegistrar\":[],\"RtcIdentityValidationResult\":[],\"RtcInboundRtpStreamStats\":[],\"RtcMediaStreamStats\":[],\"RtcMediaStreamTrackStats\":[],\"RtcOfferAnswerOptions\":[],\"RtcOfferOptions\":[],\"RtcOutboundRtpStreamStats\":[],\"RtcPeerConnection\":[\"EventTarget\"],\"RtcPeerConnectionIceErrorEvent\":[\"Event\"],\"RtcPeerConnectionIceEvent\":[\"Event\"],\"RtcPeerConnectionIceEventInit\":[],\"RtcPeerConnectionState\":[],\"RtcPriorityType\":[],\"RtcRtcpParameters\":[],\"RtcRtpCapabilities\":[],\"RtcRtpCodecCapability\":[],\"RtcRtpCodecParameters\":[],\"RtcRtpContributingSource\":[],\"RtcRtpEncodingParameters\":[],\"RtcRtpHeaderExtensionCapability\":[],\"RtcRtpHeaderExtensionParameters\":[],\"RtcRtpParameters\":[],\"RtcRtpReceiver\":[],\"RtcRtpScriptTransform\":[],\"RtcRtpScriptTransformer\":[\"EventTarget\"],\"RtcRtpSender\":[],\"RtcRtpSourceEntry\":[],\"RtcRtpSourceEntryType\":[],\"RtcRtpSynchronizationSource\":[],\"RtcRtpTransceiver\":[],\"RtcRtpTransceiverDirection\":[],\"RtcRtpTransceiverInit\":[],\"RtcRtxParameters\":[],\"RtcSdpType\":[],\"RtcSessionDescription\":[],\"RtcSessionDescriptionInit\":[],\"RtcSignalingState\":[],\"RtcStats\":[],\"RtcStatsIceCandidatePairState\":[],\"RtcStatsIceCandidateType\":[],\"RtcStatsReport\":[],\"RtcStatsReportInternal\":[],\"RtcStatsType\":[],\"RtcTrackEvent\":[\"Event\"],\"RtcTrackEventInit\":[],\"RtcTransformEvent\":[\"Event\"],\"RtcTransportStats\":[],\"RtcdtmfSender\":[\"EventTarget\"],\"RtcdtmfToneChangeEvent\":[\"Event\"],\"RtcdtmfToneChangeEventInit\":[],\"RtcrtpContributingSourceStats\":[],\"RtcrtpStreamStats\":[],\"SFrameTransform\":[\"EventTarget\"],\"SFrameTransformErrorEvent\":[\"Event\"],\"SFrameTransformErrorEventInit\":[],\"SFrameTransformErrorEventType\":[],\"SFrameTransformOptions\":[],\"SFrameTransformRole\":[],\"SaveFilePickerOptions\":[],\"Scheduler\":[],\"SchedulerPostTaskOptions\":[],\"Scheduling\":[],\"Screen\":[\"EventTarget\"],\"ScreenColorGamut\":[],\"ScreenDetailed\":[\"EventTarget\",\"Screen\"],\"ScreenDetails\":[\"EventTarget\"],\"ScreenLuminance\":[],\"ScreenOrientation\":[\"EventTarget\"],\"ScriptProcessorNode\":[\"AudioNode\",\"EventTarget\"],\"ScrollAreaEvent\":[\"Event\",\"UiEvent\"],\"ScrollBehavior\":[],\"ScrollBoxObject\":[],\"ScrollIntoViewContainer\":[],\"ScrollIntoViewOptions\":[],\"ScrollLogicalPosition\":[],\"ScrollOptions\":[],\"ScrollRestoration\":[],\"ScrollSetting\":[],\"ScrollState\":[],\"ScrollToOptions\":[],\"ScrollViewChangeEventInit\":[],\"SecurityPolicyViolationEvent\":[\"Event\"],\"SecurityPolicyViolationEventDisposition\":[],\"SecurityPolicyViolationEventInit\":[],\"Selection\":[],\"SelectionMode\":[],\"Serial\":[\"EventTarget\"],\"SerialInputSignals\":[],\"SerialOptions\":[],\"SerialOutputSignals\":[],\"SerialPort\":[\"EventTarget\"],\"SerialPortFilter\":[],\"SerialPortInfo\":[],\"SerialPortRequestOptions\":[],\"ServerSocketOptions\":[],\"ServiceWorker\":[\"EventTarget\"],\"ServiceWorkerContainer\":[\"EventTarget\"],\"ServiceWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"ServiceWorkerRegistration\":[\"EventTarget\"],\"ServiceWorkerState\":[],\"ServiceWorkerUpdateViaCache\":[],\"ShadowRoot\":[\"DocumentFragment\",\"EventTarget\",\"Node\"],\"ShadowRootInit\":[],\"ShadowRootMode\":[],\"ShareData\":[],\"SharedWorker\":[\"EventTarget\"],\"SharedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"ShowPopoverOptions\":[],\"SignResponse\":[],\"SocketElement\":[],\"SocketOptions\":[],\"SocketReadyState\":[],\"SocketsDict\":[],\"SourceBuffer\":[\"EventTarget\"],\"SourceBufferAppendMode\":[],\"SourceBufferList\":[\"EventTarget\"],\"SpeechGrammar\":[],\"SpeechGrammarList\":[],\"SpeechRecognition\":[\"EventTarget\"],\"SpeechRecognitionAlternative\":[],\"SpeechRecognitionError\":[\"Event\"],\"SpeechRecognitionErrorCode\":[],\"SpeechRecognitionErrorInit\":[],\"SpeechRecognitionEvent\":[\"Event\"],\"SpeechRecognitionEventInit\":[],\"SpeechRecognitionResult\":[],\"SpeechRecognitionResultList\":[],\"SpeechSynthesis\":[\"EventTarget\"],\"SpeechSynthesisErrorCode\":[],\"SpeechSynthesisErrorEvent\":[\"Event\",\"SpeechSynthesisEvent\"],\"SpeechSynthesisErrorEventInit\":[],\"SpeechSynthesisEvent\":[\"Event\"],\"SpeechSynthesisEventInit\":[],\"SpeechSynthesisUtterance\":[\"EventTarget\"],\"SpeechSynthesisVoice\":[],\"StartViewTransitionOptions\":[],\"StaticRange\":[\"AbstractRange\"],\"StaticRangeInit\":[],\"StereoPannerNode\":[\"AudioNode\",\"EventTarget\"],\"StereoPannerOptions\":[],\"Storage\":[],\"StorageEstimate\":[],\"StorageEvent\":[\"Event\"],\"StorageEventInit\":[],\"StorageManager\":[],\"StorageType\":[],\"StreamPipeOptions\":[],\"StyleRuleChangeEventInit\":[],\"StyleSheet\":[],\"StyleSheetApplicableStateChangeEventInit\":[],\"StyleSheetChangeEventInit\":[],\"StyleSheetList\":[],\"SubmitEvent\":[\"Event\"],\"SubmitEventInit\":[],\"SubtleCrypto\":[],\"SupportedType\":[],\"SvcOutputMetadata\":[],\"SvgAngle\":[],\"SvgAnimateElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateMotionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateTransformElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimatedAngle\":[],\"SvgAnimatedBoolean\":[],\"SvgAnimatedEnumeration\":[],\"SvgAnimatedInteger\":[],\"SvgAnimatedLength\":[],\"SvgAnimatedLengthList\":[],\"SvgAnimatedNumber\":[],\"SvgAnimatedNumberList\":[],\"SvgAnimatedPreserveAspectRatio\":[],\"SvgAnimatedRect\":[],\"SvgAnimatedString\":[],\"SvgAnimatedTransformList\":[],\"SvgAnimationElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgBoundingBoxOptions\":[],\"SvgCircleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgClipPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgComponentTransferFunctionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgDefsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgDescElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgElement\":[\"Element\",\"EventTarget\",\"Node\"],\"SvgEllipseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgFilterElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgForeignObjectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGeometryElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgGraphicsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgLength\":[],\"SvgLengthList\":[],\"SvgLineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgLinearGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgMarkerElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMaskElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMatrix\":[],\"SvgMetadataElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgNumber\":[],\"SvgNumberList\":[],\"SvgPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPathSeg\":[],\"SvgPathSegArcAbs\":[\"SvgPathSeg\"],\"SvgPathSegArcRel\":[\"SvgPathSeg\"],\"SvgPathSegClosePath\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalRel\":[\"SvgPathSeg\"],\"SvgPathSegList\":[],\"SvgPathSegMovetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegMovetoRel\":[\"SvgPathSeg\"],\"SvgPatternElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgPoint\":[],\"SvgPointList\":[],\"SvgPolygonElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPolylineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPreserveAspectRatio\":[],\"SvgRadialGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgRect\":[],\"SvgRectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgScriptElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgStopElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgStringList\":[],\"SvgStyleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSwitchElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgSymbolElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTextContentElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgTextElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"SvgTextPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTextPositioningElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTitleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTransform\":[],\"SvgTransformList\":[],\"SvgUnitTypes\":[],\"SvgUseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgViewElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgZoomAndPan\":[],\"SvgaElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgfeBlendElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeColorMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeComponentTransferElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeCompositeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeConvolveMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDiffuseLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDisplacementMapElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDistantLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDropShadowElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFloodElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFuncAElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncBElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncGElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncRElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeGaussianBlurElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeNodeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMorphologyElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeOffsetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfePointLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpecularLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpotLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTileElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTurbulenceElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvggElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgmPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgsvgElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgtSpanElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"TaskController\":[\"AbortController\"],\"TaskControllerInit\":[],\"TaskPriority\":[],\"TaskPriorityChangeEvent\":[\"Event\"],\"TaskPriorityChangeEventInit\":[],\"TaskSignal\":[\"AbortSignal\",\"EventTarget\"],\"TaskSignalAnyInit\":[],\"TcpReadyState\":[],\"TcpServerSocket\":[\"EventTarget\"],\"TcpServerSocketEvent\":[\"Event\"],\"TcpServerSocketEventInit\":[],\"TcpSocket\":[\"EventTarget\"],\"TcpSocketBinaryType\":[],\"TcpSocketErrorEvent\":[\"Event\"],\"TcpSocketErrorEventInit\":[],\"TcpSocketEvent\":[\"Event\"],\"TcpSocketEventInit\":[],\"Text\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"TextDecodeOptions\":[],\"TextDecoder\":[],\"TextDecoderOptions\":[],\"TextEncoder\":[],\"TextMetrics\":[],\"TextTrack\":[\"EventTarget\"],\"TextTrackCue\":[\"EventTarget\"],\"TextTrackCueList\":[],\"TextTrackKind\":[],\"TextTrackList\":[\"EventTarget\"],\"TextTrackMode\":[],\"TimeEvent\":[\"Event\"],\"TimeRanges\":[],\"ToggleEvent\":[\"Event\"],\"ToggleEventInit\":[],\"TogglePopoverOptions\":[],\"TokenBinding\":[],\"TokenBindingStatus\":[],\"Touch\":[],\"TouchEvent\":[\"Event\",\"UiEvent\"],\"TouchEventInit\":[],\"TouchInit\":[],\"TouchList\":[],\"TrackEvent\":[\"Event\"],\"TrackEventInit\":[],\"TransformStream\":[],\"TransformStreamDefaultController\":[],\"Transformer\":[],\"TransitionEvent\":[\"Event\"],\"TransitionEventInit\":[],\"Transport\":[],\"TreeBoxObject\":[],\"TreeCellInfo\":[],\"TreeView\":[],\"TreeWalker\":[],\"U2f\":[],\"U2fClientData\":[],\"ULongRange\":[],\"UaDataValues\":[],\"UaLowEntropyJson\":[],\"UdpMessageEventInit\":[],\"UdpOptions\":[],\"UiEvent\":[\"Event\"],\"UiEventInit\":[],\"UnderlyingSink\":[],\"UnderlyingSource\":[],\"Url\":[],\"UrlSearchParams\":[],\"Usb\":[\"EventTarget\"],\"UsbAlternateInterface\":[],\"UsbConfiguration\":[],\"UsbConnectionEvent\":[\"Event\"],\"UsbConnectionEventInit\":[],\"UsbControlTransferParameters\":[],\"UsbDevice\":[],\"UsbDeviceFilter\":[],\"UsbDeviceRequestOptions\":[],\"UsbDirection\":[],\"UsbEndpoint\":[],\"UsbEndpointType\":[],\"UsbInTransferResult\":[],\"UsbInterface\":[],\"UsbIsochronousInTransferPacket\":[],\"UsbIsochronousInTransferResult\":[],\"UsbIsochronousOutTransferPacket\":[],\"UsbIsochronousOutTransferResult\":[],\"UsbOutTransferResult\":[],\"UsbPermissionDescriptor\":[],\"UsbPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"UsbPermissionStorage\":[],\"UsbRecipient\":[],\"UsbRequestType\":[],\"UsbTransferStatus\":[],\"UserActivation\":[],\"UserProximityEvent\":[\"Event\"],\"UserProximityEventInit\":[],\"UserVerificationRequirement\":[],\"ValidityState\":[],\"ValueEvent\":[\"Event\"],\"ValueEventInit\":[],\"VideoColorPrimaries\":[],\"VideoColorSpace\":[],\"VideoColorSpaceInit\":[],\"VideoConfiguration\":[],\"VideoDecoder\":[\"EventTarget\"],\"VideoDecoderConfig\":[],\"VideoDecoderInit\":[],\"VideoDecoderSupport\":[],\"VideoEncoder\":[\"EventTarget\"],\"VideoEncoderBitrateMode\":[],\"VideoEncoderConfig\":[],\"VideoEncoderEncodeOptions\":[],\"VideoEncoderInit\":[],\"VideoEncoderSupport\":[],\"VideoFacingModeEnum\":[],\"VideoFrame\":[],\"VideoFrameBufferInit\":[],\"VideoFrameCopyToOptions\":[],\"VideoFrameInit\":[],\"VideoFrameMetadata\":[],\"VideoMatrixCoefficients\":[],\"VideoPixelFormat\":[],\"VideoPlaybackQuality\":[],\"VideoStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"VideoTrack\":[],\"VideoTrackList\":[\"EventTarget\"],\"VideoTransferCharacteristics\":[],\"ViewTransition\":[],\"ViewTransitionTypeSet\":[],\"VisibilityState\":[],\"VisualViewport\":[\"EventTarget\"],\"VoidCallback\":[],\"VrDisplay\":[\"EventTarget\"],\"VrDisplayCapabilities\":[],\"VrEye\":[],\"VrEyeParameters\":[],\"VrFieldOfView\":[],\"VrFrameData\":[],\"VrLayer\":[],\"VrMockController\":[],\"VrMockDisplay\":[],\"VrPose\":[],\"VrServiceTest\":[],\"VrStageParameters\":[],\"VrSubmitFrameResult\":[],\"VttCue\":[\"EventTarget\",\"TextTrackCue\"],\"VttRegion\":[],\"WakeLock\":[],\"WakeLockSentinel\":[\"EventTarget\"],\"WakeLockType\":[],\"WatchAdvertisementsOptions\":[],\"WaveShaperNode\":[\"AudioNode\",\"EventTarget\"],\"WaveShaperOptions\":[],\"WebGl2RenderingContext\":[],\"WebGlActiveInfo\":[],\"WebGlBuffer\":[],\"WebGlContextAttributes\":[],\"WebGlContextEvent\":[\"Event\"],\"WebGlContextEventInit\":[],\"WebGlFramebuffer\":[],\"WebGlPowerPreference\":[],\"WebGlProgram\":[],\"WebGlQuery\":[],\"WebGlRenderbuffer\":[],\"WebGlRenderingContext\":[],\"WebGlSampler\":[],\"WebGlShader\":[],\"WebGlShaderPrecisionFormat\":[],\"WebGlSync\":[],\"WebGlTexture\":[],\"WebGlTransformFeedback\":[],\"WebGlUniformLocation\":[],\"WebGlVertexArrayObject\":[],\"WebKitCssMatrix\":[\"DomMatrix\",\"DomMatrixReadOnly\"],\"WebSocket\":[\"EventTarget\"],\"WebSocketDict\":[],\"WebSocketElement\":[],\"WebTransport\":[],\"WebTransportBidirectionalStream\":[],\"WebTransportCloseInfo\":[],\"WebTransportCongestionControl\":[],\"WebTransportDatagramDuplexStream\":[],\"WebTransportDatagramStats\":[],\"WebTransportError\":[\"DomException\"],\"WebTransportErrorOptions\":[],\"WebTransportErrorSource\":[],\"WebTransportHash\":[],\"WebTransportOptions\":[],\"WebTransportReceiveStream\":[\"ReadableStream\"],\"WebTransportReceiveStreamStats\":[],\"WebTransportReliabilityMode\":[],\"WebTransportSendStream\":[\"WritableStream\"],\"WebTransportSendStreamOptions\":[],\"WebTransportSendStreamStats\":[],\"WebTransportStats\":[],\"WebglColorBufferFloat\":[],\"WebglCompressedTextureAstc\":[],\"WebglCompressedTextureAtc\":[],\"WebglCompressedTextureEtc\":[],\"WebglCompressedTextureEtc1\":[],\"WebglCompressedTexturePvrtc\":[],\"WebglCompressedTextureS3tc\":[],\"WebglCompressedTextureS3tcSrgb\":[],\"WebglDebugRendererInfo\":[],\"WebglDebugShaders\":[],\"WebglDepthTexture\":[],\"WebglDrawBuffers\":[],\"WebglLoseContext\":[],\"WebglMultiDraw\":[],\"WellKnownDirectory\":[],\"WgslLanguageFeatures\":[],\"WheelEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"WheelEventInit\":[],\"WidevineCdmManifest\":[],\"Window\":[\"EventTarget\"],\"WindowClient\":[\"Client\"],\"Worker\":[\"EventTarget\"],\"WorkerDebuggerGlobalScope\":[\"EventTarget\"],\"WorkerGlobalScope\":[\"EventTarget\"],\"WorkerLocation\":[],\"WorkerNavigator\":[],\"WorkerOptions\":[],\"WorkerType\":[],\"Worklet\":[],\"WorkletGlobalScope\":[],\"WorkletOptions\":[],\"WritableStream\":[],\"WritableStreamDefaultController\":[],\"WritableStreamDefaultWriter\":[],\"WriteCommandType\":[],\"WriteParams\":[],\"XPathExpression\":[],\"XPathNsResolver\":[],\"XPathResult\":[],\"XmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"XmlHttpRequest\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlHttpRequestEventTarget\":[\"EventTarget\"],\"XmlHttpRequestResponseType\":[],\"XmlHttpRequestUpload\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlSerializer\":[],\"XrBoundedReferenceSpace\":[\"EventTarget\",\"XrReferenceSpace\",\"XrSpace\"],\"XrEye\":[],\"XrFrame\":[],\"XrHand\":[],\"XrHandJoint\":[],\"XrHandedness\":[],\"XrInputSource\":[],\"XrInputSourceArray\":[],\"XrInputSourceEvent\":[\"Event\"],\"XrInputSourceEventInit\":[],\"XrInputSourcesChangeEvent\":[\"Event\"],\"XrInputSourcesChangeEventInit\":[],\"XrJointPose\":[\"XrPose\"],\"XrJointSpace\":[\"EventTarget\",\"XrSpace\"],\"XrLayer\":[\"EventTarget\"],\"XrPermissionDescriptor\":[],\"XrPermissionStatus\":[\"EventTarget\",\"PermissionStatus\"],\"XrPose\":[],\"XrReferenceSpace\":[\"EventTarget\",\"XrSpace\"],\"XrReferenceSpaceEvent\":[\"Event\"],\"XrReferenceSpaceEventInit\":[],\"XrReferenceSpaceType\":[],\"XrRenderState\":[],\"XrRenderStateInit\":[],\"XrRigidTransform\":[],\"XrSession\":[\"EventTarget\"],\"XrSessionEvent\":[\"Event\"],\"XrSessionEventInit\":[],\"XrSessionInit\":[],\"XrSessionMode\":[],\"XrSessionSupportedPermissionDescriptor\":[],\"XrSpace\":[\"EventTarget\"],\"XrSystem\":[\"EventTarget\"],\"XrTargetRayMode\":[],\"XrView\":[],\"XrViewerPose\":[\"XrPose\"],\"XrViewport\":[],\"XrVisibilityState\":[],\"XrWebGlLayer\":[\"EventTarget\",\"XrLayer\"],\"XrWebGlLayerInit\":[],\"XsltProcessor\":[],\"console\":[],\"css\":[],\"default\":[\"std\"],\"gpu_buffer_usage\":[],\"gpu_color_write\":[],\"gpu_map_mode\":[],\"gpu_shader_stage\":[],\"gpu_texture_usage\":[],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\"]}}", + "web-sys_0.3.82": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.82\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"}],\"features\":{\"AbortController\":[],\"AbortSignal\":[\"EventTarget\"],\"AddEventListenerOptions\":[],\"AesCbcParams\":[],\"AesCtrParams\":[],\"AesDerivedKeyParams\":[],\"AesGcmParams\":[],\"AesKeyAlgorithm\":[],\"AesKeyGenParams\":[],\"Algorithm\":[],\"AlignSetting\":[],\"AllowedBluetoothDevice\":[],\"AllowedUsbDevice\":[],\"AlphaOption\":[],\"AnalyserNode\":[\"AudioNode\",\"EventTarget\"],\"AnalyserOptions\":[],\"AngleInstancedArrays\":[],\"Animation\":[\"EventTarget\"],\"AnimationEffect\":[],\"AnimationEvent\":[\"Event\"],\"AnimationEventInit\":[],\"AnimationPlayState\":[],\"AnimationPlaybackEvent\":[\"Event\"],\"AnimationPlaybackEventInit\":[],\"AnimationPropertyDetails\":[],\"AnimationPropertyValueDetails\":[],\"AnimationTimeline\":[],\"AssignedNodesOptions\":[],\"AttestationConveyancePreference\":[],\"Attr\":[\"EventTarget\",\"Node\"],\"AttributeNameValue\":[],\"AudioBuffer\":[],\"AudioBufferOptions\":[],\"AudioBufferSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"AudioBufferSourceOptions\":[],\"AudioConfiguration\":[],\"AudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"AudioContextLatencyCategory\":[],\"AudioContextOptions\":[],\"AudioContextState\":[],\"AudioData\":[],\"AudioDataCopyToOptions\":[],\"AudioDataInit\":[],\"AudioDecoder\":[],\"AudioDecoderConfig\":[],\"AudioDecoderInit\":[],\"AudioDecoderSupport\":[],\"AudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"AudioEncoder\":[],\"AudioEncoderConfig\":[],\"AudioEncoderInit\":[],\"AudioEncoderSupport\":[],\"AudioListener\":[],\"AudioNode\":[\"EventTarget\"],\"AudioNodeOptions\":[],\"AudioParam\":[],\"AudioParamMap\":[],\"AudioProcessingEvent\":[\"Event\"],\"AudioSampleFormat\":[],\"AudioScheduledSourceNode\":[\"AudioNode\",\"EventTarget\"],\"AudioSinkInfo\":[],\"AudioSinkOptions\":[],\"AudioSinkType\":[],\"AudioStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"AudioTrack\":[],\"AudioTrackList\":[\"EventTarget\"],\"AudioWorklet\":[\"Worklet\"],\"AudioWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"AudioWorkletNode\":[\"AudioNode\",\"EventTarget\"],\"AudioWorkletNodeOptions\":[],\"AudioWorkletProcessor\":[],\"AuthenticationExtensionsClientInputs\":[],\"AuthenticationExtensionsClientInputsJson\":[],\"AuthenticationExtensionsClientOutputs\":[],\"AuthenticationExtensionsClientOutputsJson\":[],\"AuthenticationExtensionsDevicePublicKeyInputs\":[],\"AuthenticationExtensionsDevicePublicKeyOutputs\":[],\"AuthenticationExtensionsLargeBlobInputs\":[],\"AuthenticationExtensionsLargeBlobOutputs\":[],\"AuthenticationExtensionsPrfInputs\":[],\"AuthenticationExtensionsPrfOutputs\":[],\"AuthenticationExtensionsPrfValues\":[],\"AuthenticationResponseJson\":[],\"AuthenticatorAssertionResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAssertionResponseJson\":[],\"AuthenticatorAttachment\":[],\"AuthenticatorAttestationResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAttestationResponseJson\":[],\"AuthenticatorResponse\":[],\"AuthenticatorSelectionCriteria\":[],\"AuthenticatorTransport\":[],\"AutoKeyword\":[],\"AutocompleteInfo\":[],\"BarProp\":[],\"BaseAudioContext\":[\"EventTarget\"],\"BaseComputedKeyframe\":[],\"BaseKeyframe\":[],\"BasePropertyIndexedKeyframe\":[],\"BasicCardRequest\":[],\"BasicCardResponse\":[],\"BasicCardType\":[],\"BatteryManager\":[\"EventTarget\"],\"BeforeUnloadEvent\":[\"Event\"],\"BinaryType\":[],\"BiquadFilterNode\":[\"AudioNode\",\"EventTarget\"],\"BiquadFilterOptions\":[],\"BiquadFilterType\":[],\"Blob\":[],\"BlobEvent\":[\"Event\"],\"BlobEventInit\":[],\"BlobPropertyBag\":[],\"BlockParsingOptions\":[],\"Bluetooth\":[\"EventTarget\"],\"BluetoothAdvertisingEvent\":[\"Event\"],\"BluetoothAdvertisingEventInit\":[],\"BluetoothCharacteristicProperties\":[],\"BluetoothDataFilterInit\":[],\"BluetoothDevice\":[\"EventTarget\"],\"BluetoothLeScanFilterInit\":[],\"BluetoothManufacturerDataMap\":[],\"BluetoothPermissionDescriptor\":[],\"BluetoothPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"BluetoothPermissionStorage\":[],\"BluetoothRemoteGattCharacteristic\":[\"EventTarget\"],\"BluetoothRemoteGattDescriptor\":[],\"BluetoothRemoteGattServer\":[],\"BluetoothRemoteGattService\":[\"EventTarget\"],\"BluetoothServiceDataMap\":[],\"BluetoothUuid\":[],\"BoxQuadOptions\":[],\"BroadcastChannel\":[\"EventTarget\"],\"BrowserElementDownloadOptions\":[],\"BrowserElementExecuteScriptOptions\":[],\"BrowserFeedWriter\":[],\"BrowserFindCaseSensitivity\":[],\"BrowserFindDirection\":[],\"ByteLengthQueuingStrategy\":[],\"Cache\":[],\"CacheBatchOperation\":[],\"CacheQueryOptions\":[],\"CacheStorage\":[],\"CacheStorageNamespace\":[],\"CanvasCaptureMediaStream\":[\"EventTarget\",\"MediaStream\"],\"CanvasCaptureMediaStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"CanvasGradient\":[],\"CanvasPattern\":[],\"CanvasRenderingContext2d\":[],\"CanvasWindingRule\":[],\"CaretChangedReason\":[],\"CaretPosition\":[],\"CaretStateChangedEventInit\":[],\"CdataSection\":[\"CharacterData\",\"EventTarget\",\"Node\",\"Text\"],\"ChannelCountMode\":[],\"ChannelInterpretation\":[],\"ChannelMergerNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelMergerOptions\":[],\"ChannelSplitterNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelSplitterOptions\":[],\"CharacterData\":[\"EventTarget\",\"Node\"],\"CheckerboardReason\":[],\"CheckerboardReport\":[],\"CheckerboardReportService\":[],\"ChromeFilePropertyBag\":[],\"ChromeWorker\":[\"EventTarget\",\"Worker\"],\"Client\":[],\"ClientQueryOptions\":[],\"ClientRectsAndTexts\":[],\"ClientType\":[],\"Clients\":[],\"Clipboard\":[\"EventTarget\"],\"ClipboardEvent\":[\"Event\"],\"ClipboardEventInit\":[],\"ClipboardItem\":[],\"ClipboardItemOptions\":[],\"ClipboardPermissionDescriptor\":[],\"ClipboardUnsanitizedFormats\":[],\"CloseEvent\":[\"Event\"],\"CloseEventInit\":[],\"CodecState\":[],\"CollectedClientData\":[],\"ColorSpaceConversion\":[],\"Comment\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"CompositeOperation\":[],\"CompositionEvent\":[\"Event\",\"UiEvent\"],\"CompositionEventInit\":[],\"CompressionFormat\":[],\"CompressionStream\":[],\"ComputedEffectTiming\":[],\"ConnStatusDict\":[],\"ConnectionType\":[],\"ConsoleCounter\":[],\"ConsoleCounterError\":[],\"ConsoleEvent\":[],\"ConsoleInstance\":[],\"ConsoleInstanceOptions\":[],\"ConsoleLevel\":[],\"ConsoleLogLevel\":[],\"ConsoleProfileEvent\":[],\"ConsoleStackEntry\":[],\"ConsoleTimerError\":[],\"ConsoleTimerLogOrEnd\":[],\"ConsoleTimerStart\":[],\"ConstantSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"ConstantSourceOptions\":[],\"ConstrainBooleanParameters\":[],\"ConstrainDomStringParameters\":[],\"ConstrainDoubleRange\":[],\"ConstrainLongRange\":[],\"ContextAttributes2d\":[],\"ConvertCoordinateOptions\":[],\"ConvolverNode\":[\"AudioNode\",\"EventTarget\"],\"ConvolverOptions\":[],\"CookieChangeEvent\":[\"Event\"],\"CookieChangeEventInit\":[],\"CookieInit\":[],\"CookieListItem\":[],\"CookieSameSite\":[],\"CookieStore\":[\"EventTarget\"],\"CookieStoreDeleteOptions\":[],\"CookieStoreGetOptions\":[],\"CookieStoreManager\":[],\"Coordinates\":[],\"CountQueuingStrategy\":[],\"Credential\":[],\"CredentialCreationOptions\":[],\"CredentialPropertiesOutput\":[],\"CredentialRequestOptions\":[],\"CredentialsContainer\":[],\"Crypto\":[],\"CryptoKey\":[],\"CryptoKeyPair\":[],\"CssAnimation\":[\"Animation\",\"EventTarget\"],\"CssBoxType\":[],\"CssConditionRule\":[\"CssGroupingRule\",\"CssRule\"],\"CssCounterStyleRule\":[\"CssRule\"],\"CssFontFaceRule\":[\"CssRule\"],\"CssFontFeatureValuesRule\":[\"CssRule\"],\"CssGroupingRule\":[\"CssRule\"],\"CssImportRule\":[\"CssRule\"],\"CssKeyframeRule\":[\"CssRule\"],\"CssKeyframesRule\":[\"CssRule\"],\"CssMediaRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssNamespaceRule\":[\"CssRule\"],\"CssPageRule\":[\"CssRule\"],\"CssPseudoElement\":[],\"CssRule\":[],\"CssRuleList\":[],\"CssStyleDeclaration\":[],\"CssStyleRule\":[\"CssRule\"],\"CssStyleSheet\":[\"StyleSheet\"],\"CssStyleSheetParsingMode\":[],\"CssSupportsRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssTransition\":[\"Animation\",\"EventTarget\"],\"CustomElementRegistry\":[],\"CustomEvent\":[\"Event\"],\"CustomEventInit\":[],\"DataTransfer\":[],\"DataTransferItem\":[],\"DataTransferItemList\":[],\"DateTimeValue\":[],\"DecoderDoctorNotification\":[],\"DecoderDoctorNotificationType\":[],\"DecompressionStream\":[],\"DedicatedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"DelayNode\":[\"AudioNode\",\"EventTarget\"],\"DelayOptions\":[],\"DeviceAcceleration\":[],\"DeviceAccelerationInit\":[],\"DeviceLightEvent\":[\"Event\"],\"DeviceLightEventInit\":[],\"DeviceMotionEvent\":[\"Event\"],\"DeviceMotionEventInit\":[],\"DeviceOrientationEvent\":[\"Event\"],\"DeviceOrientationEventInit\":[],\"DeviceProximityEvent\":[\"Event\"],\"DeviceProximityEventInit\":[],\"DeviceRotationRate\":[],\"DeviceRotationRateInit\":[],\"DhKeyDeriveParams\":[],\"DirectionSetting\":[],\"Directory\":[],\"DirectoryPickerOptions\":[],\"DisplayMediaStreamConstraints\":[],\"DisplayNameOptions\":[],\"DisplayNameResult\":[],\"DistanceModelType\":[],\"DnsCacheDict\":[],\"DnsCacheEntry\":[],\"DnsLookupDict\":[],\"Document\":[\"EventTarget\",\"Node\"],\"DocumentFragment\":[\"EventTarget\",\"Node\"],\"DocumentTimeline\":[\"AnimationTimeline\"],\"DocumentTimelineOptions\":[],\"DocumentType\":[\"EventTarget\",\"Node\"],\"DomError\":[],\"DomException\":[],\"DomImplementation\":[],\"DomMatrix\":[\"DomMatrixReadOnly\"],\"DomMatrix2dInit\":[],\"DomMatrixInit\":[],\"DomMatrixReadOnly\":[],\"DomParser\":[],\"DomPoint\":[\"DomPointReadOnly\"],\"DomPointInit\":[],\"DomPointReadOnly\":[],\"DomQuad\":[],\"DomQuadInit\":[],\"DomQuadJson\":[],\"DomRect\":[\"DomRectReadOnly\"],\"DomRectInit\":[],\"DomRectList\":[],\"DomRectReadOnly\":[],\"DomRequest\":[\"EventTarget\"],\"DomRequestReadyState\":[],\"DomStringList\":[],\"DomStringMap\":[],\"DomTokenList\":[],\"DomWindowResizeEventDetail\":[],\"DoubleRange\":[],\"DragEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"DragEventInit\":[],\"DynamicsCompressorNode\":[\"AudioNode\",\"EventTarget\"],\"DynamicsCompressorOptions\":[],\"EcKeyAlgorithm\":[],\"EcKeyGenParams\":[],\"EcKeyImportParams\":[],\"EcdhKeyDeriveParams\":[],\"EcdsaParams\":[],\"EffectTiming\":[],\"Element\":[\"EventTarget\",\"Node\"],\"ElementCreationOptions\":[],\"ElementDefinitionOptions\":[],\"EncodedAudioChunk\":[],\"EncodedAudioChunkInit\":[],\"EncodedAudioChunkMetadata\":[],\"EncodedAudioChunkType\":[],\"EncodedVideoChunk\":[],\"EncodedVideoChunkInit\":[],\"EncodedVideoChunkMetadata\":[],\"EncodedVideoChunkType\":[],\"EndingTypes\":[],\"ErrorCallback\":[],\"ErrorEvent\":[\"Event\"],\"ErrorEventInit\":[],\"Event\":[],\"EventInit\":[],\"EventListener\":[],\"EventListenerOptions\":[],\"EventModifierInit\":[],\"EventSource\":[\"EventTarget\"],\"EventSourceInit\":[],\"EventTarget\":[],\"Exception\":[],\"ExtBlendMinmax\":[],\"ExtColorBufferFloat\":[],\"ExtColorBufferHalfFloat\":[],\"ExtDisjointTimerQuery\":[],\"ExtFragDepth\":[],\"ExtSRgb\":[],\"ExtShaderTextureLod\":[],\"ExtTextureFilterAnisotropic\":[],\"ExtTextureNorm16\":[],\"ExtendableCookieChangeEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableCookieChangeEventInit\":[],\"ExtendableEvent\":[\"Event\"],\"ExtendableEventInit\":[],\"ExtendableMessageEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableMessageEventInit\":[],\"External\":[],\"FakePluginMimeEntry\":[],\"FakePluginTagInit\":[],\"FetchEvent\":[\"Event\",\"ExtendableEvent\"],\"FetchEventInit\":[],\"FetchObserver\":[\"EventTarget\"],\"FetchReadableStreamReadDataArray\":[],\"FetchReadableStreamReadDataDone\":[],\"FetchState\":[],\"File\":[\"Blob\"],\"FileCallback\":[],\"FileList\":[],\"FilePickerAcceptType\":[],\"FilePickerOptions\":[],\"FilePropertyBag\":[],\"FileReader\":[\"EventTarget\"],\"FileReaderSync\":[],\"FileSystem\":[],\"FileSystemCreateWritableOptions\":[],\"FileSystemDirectoryEntry\":[\"FileSystemEntry\"],\"FileSystemDirectoryHandle\":[\"FileSystemHandle\"],\"FileSystemDirectoryReader\":[],\"FileSystemEntriesCallback\":[],\"FileSystemEntry\":[],\"FileSystemEntryCallback\":[],\"FileSystemFileEntry\":[\"FileSystemEntry\"],\"FileSystemFileHandle\":[\"FileSystemHandle\"],\"FileSystemFlags\":[],\"FileSystemGetDirectoryOptions\":[],\"FileSystemGetFileOptions\":[],\"FileSystemHandle\":[],\"FileSystemHandleKind\":[],\"FileSystemHandlePermissionDescriptor\":[],\"FileSystemPermissionDescriptor\":[],\"FileSystemPermissionMode\":[],\"FileSystemReadWriteOptions\":[],\"FileSystemRemoveOptions\":[],\"FileSystemSyncAccessHandle\":[],\"FileSystemWritableFileStream\":[\"WritableStream\"],\"FillMode\":[],\"FlashClassification\":[],\"FlowControlType\":[],\"FocusEvent\":[\"Event\",\"UiEvent\"],\"FocusEventInit\":[],\"FocusOptions\":[],\"FontData\":[],\"FontFace\":[],\"FontFaceDescriptors\":[],\"FontFaceLoadStatus\":[],\"FontFaceSet\":[\"EventTarget\"],\"FontFaceSetIterator\":[],\"FontFaceSetIteratorResult\":[],\"FontFaceSetLoadEvent\":[\"Event\"],\"FontFaceSetLoadEventInit\":[],\"FontFaceSetLoadStatus\":[],\"FormData\":[],\"FrameType\":[],\"FuzzingFunctions\":[],\"GainNode\":[\"AudioNode\",\"EventTarget\"],\"GainOptions\":[],\"Gamepad\":[],\"GamepadButton\":[],\"GamepadEffectParameters\":[],\"GamepadEvent\":[\"Event\"],\"GamepadEventInit\":[],\"GamepadHand\":[],\"GamepadHapticActuator\":[],\"GamepadHapticActuatorType\":[],\"GamepadHapticEffectType\":[],\"GamepadHapticsResult\":[],\"GamepadMappingType\":[],\"GamepadPose\":[],\"GamepadTouch\":[],\"Geolocation\":[],\"GestureEvent\":[\"Event\",\"UiEvent\"],\"GetAnimationsOptions\":[],\"GetRootNodeOptions\":[],\"GetUserMediaRequest\":[],\"Gpu\":[],\"GpuAdapter\":[],\"GpuAdapterInfo\":[],\"GpuAddressMode\":[],\"GpuAutoLayoutMode\":[],\"GpuBindGroup\":[],\"GpuBindGroupDescriptor\":[],\"GpuBindGroupEntry\":[],\"GpuBindGroupLayout\":[],\"GpuBindGroupLayoutDescriptor\":[],\"GpuBindGroupLayoutEntry\":[],\"GpuBlendComponent\":[],\"GpuBlendFactor\":[],\"GpuBlendOperation\":[],\"GpuBlendState\":[],\"GpuBuffer\":[],\"GpuBufferBinding\":[],\"GpuBufferBindingLayout\":[],\"GpuBufferBindingType\":[],\"GpuBufferDescriptor\":[],\"GpuBufferMapState\":[],\"GpuCanvasAlphaMode\":[],\"GpuCanvasConfiguration\":[],\"GpuCanvasContext\":[],\"GpuCanvasToneMapping\":[],\"GpuCanvasToneMappingMode\":[],\"GpuColorDict\":[],\"GpuColorTargetState\":[],\"GpuCommandBuffer\":[],\"GpuCommandBufferDescriptor\":[],\"GpuCommandEncoder\":[],\"GpuCommandEncoderDescriptor\":[],\"GpuCompareFunction\":[],\"GpuCompilationInfo\":[],\"GpuCompilationMessage\":[],\"GpuCompilationMessageType\":[],\"GpuComputePassDescriptor\":[],\"GpuComputePassEncoder\":[],\"GpuComputePassTimestampWrites\":[],\"GpuComputePipeline\":[],\"GpuComputePipelineDescriptor\":[],\"GpuCopyExternalImageDestInfo\":[],\"GpuCopyExternalImageSourceInfo\":[],\"GpuCullMode\":[],\"GpuDepthStencilState\":[],\"GpuDevice\":[\"EventTarget\"],\"GpuDeviceDescriptor\":[],\"GpuDeviceLostInfo\":[],\"GpuDeviceLostReason\":[],\"GpuError\":[],\"GpuErrorFilter\":[],\"GpuExtent3dDict\":[],\"GpuExternalTexture\":[],\"GpuExternalTextureBindingLayout\":[],\"GpuExternalTextureDescriptor\":[],\"GpuFeatureName\":[],\"GpuFilterMode\":[],\"GpuFragmentState\":[],\"GpuFrontFace\":[],\"GpuIndexFormat\":[],\"GpuInternalError\":[\"GpuError\"],\"GpuLoadOp\":[],\"GpuMipmapFilterMode\":[],\"GpuMultisampleState\":[],\"GpuObjectDescriptorBase\":[],\"GpuOrigin2dDict\":[],\"GpuOrigin3dDict\":[],\"GpuOutOfMemoryError\":[\"GpuError\"],\"GpuPipelineDescriptorBase\":[],\"GpuPipelineError\":[\"DomException\"],\"GpuPipelineErrorInit\":[],\"GpuPipelineErrorReason\":[],\"GpuPipelineLayout\":[],\"GpuPipelineLayoutDescriptor\":[],\"GpuPowerPreference\":[],\"GpuPrimitiveState\":[],\"GpuPrimitiveTopology\":[],\"GpuProgrammableStage\":[],\"GpuQuerySet\":[],\"GpuQuerySetDescriptor\":[],\"GpuQueryType\":[],\"GpuQueue\":[],\"GpuQueueDescriptor\":[],\"GpuRenderBundle\":[],\"GpuRenderBundleDescriptor\":[],\"GpuRenderBundleEncoder\":[],\"GpuRenderBundleEncoderDescriptor\":[],\"GpuRenderPassColorAttachment\":[],\"GpuRenderPassDepthStencilAttachment\":[],\"GpuRenderPassDescriptor\":[],\"GpuRenderPassEncoder\":[],\"GpuRenderPassLayout\":[],\"GpuRenderPassTimestampWrites\":[],\"GpuRenderPipeline\":[],\"GpuRenderPipelineDescriptor\":[],\"GpuRequestAdapterOptions\":[],\"GpuSampler\":[],\"GpuSamplerBindingLayout\":[],\"GpuSamplerBindingType\":[],\"GpuSamplerDescriptor\":[],\"GpuShaderModule\":[],\"GpuShaderModuleCompilationHint\":[],\"GpuShaderModuleDescriptor\":[],\"GpuStencilFaceState\":[],\"GpuStencilOperation\":[],\"GpuStorageTextureAccess\":[],\"GpuStorageTextureBindingLayout\":[],\"GpuStoreOp\":[],\"GpuSupportedFeatures\":[],\"GpuSupportedLimits\":[],\"GpuTexelCopyBufferInfo\":[],\"GpuTexelCopyBufferLayout\":[],\"GpuTexelCopyTextureInfo\":[],\"GpuTexture\":[],\"GpuTextureAspect\":[],\"GpuTextureBindingLayout\":[],\"GpuTextureDescriptor\":[],\"GpuTextureDimension\":[],\"GpuTextureFormat\":[],\"GpuTextureSampleType\":[],\"GpuTextureView\":[],\"GpuTextureViewDescriptor\":[],\"GpuTextureViewDimension\":[],\"GpuUncapturedErrorEvent\":[\"Event\"],\"GpuUncapturedErrorEventInit\":[],\"GpuValidationError\":[\"GpuError\"],\"GpuVertexAttribute\":[],\"GpuVertexBufferLayout\":[],\"GpuVertexFormat\":[],\"GpuVertexState\":[],\"GpuVertexStepMode\":[],\"GroupedHistoryEventInit\":[],\"HalfOpenInfoDict\":[],\"HardwareAcceleration\":[],\"HashChangeEvent\":[\"Event\"],\"HashChangeEventInit\":[],\"Headers\":[],\"HeadersGuardEnum\":[],\"Hid\":[\"EventTarget\"],\"HidCollectionInfo\":[],\"HidConnectionEvent\":[\"Event\"],\"HidConnectionEventInit\":[],\"HidDevice\":[\"EventTarget\"],\"HidDeviceFilter\":[],\"HidDeviceRequestOptions\":[],\"HidInputReportEvent\":[\"Event\"],\"HidInputReportEventInit\":[],\"HidReportInfo\":[],\"HidReportItem\":[],\"HidUnitSystem\":[],\"HiddenPluginEventInit\":[],\"History\":[],\"HitRegionOptions\":[],\"HkdfParams\":[],\"HmacDerivedKeyParams\":[],\"HmacImportParams\":[],\"HmacKeyAlgorithm\":[],\"HmacKeyGenParams\":[],\"HtmlAllCollection\":[],\"HtmlAnchorElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAudioElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HtmlBaseElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBodyElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlButtonElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCanvasElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCollection\":[],\"HtmlDListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDetailsElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDialogElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDirectoryElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDivElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"HtmlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"HtmlEmbedElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFieldSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFontElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFormControlsCollection\":[\"HtmlCollection\"],\"HtmlFormElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadingElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHtmlElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlIFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlImageElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlInputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLabelElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLegendElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLiElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLinkElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMapElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMediaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuItemElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMetaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMeterElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlModElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlObjectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptGroupElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionsCollection\":[\"HtmlCollection\"],\"HtmlOutputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParagraphElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParamElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPictureElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPreElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlProgressElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlQuoteElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlScriptElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSelectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSlotElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSourceElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSpanElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlStyleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCaptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCellElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableColElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableRowElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableSectionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTemplateElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTextAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTimeElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTitleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTrackElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUnknownElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlVideoElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HttpConnDict\":[],\"HttpConnInfo\":[],\"HttpConnectionElement\":[],\"IdbCursor\":[],\"IdbCursorDirection\":[],\"IdbCursorWithValue\":[\"IdbCursor\"],\"IdbDatabase\":[\"EventTarget\"],\"IdbFactory\":[],\"IdbFileHandle\":[\"EventTarget\"],\"IdbFileMetadataParameters\":[],\"IdbFileRequest\":[\"DomRequest\",\"EventTarget\"],\"IdbIndex\":[],\"IdbIndexParameters\":[],\"IdbKeyRange\":[],\"IdbLocaleAwareKeyRange\":[\"IdbKeyRange\"],\"IdbMutableFile\":[\"EventTarget\"],\"IdbObjectStore\":[],\"IdbObjectStoreParameters\":[],\"IdbOpenDbOptions\":[],\"IdbOpenDbRequest\":[\"EventTarget\",\"IdbRequest\"],\"IdbRequest\":[\"EventTarget\"],\"IdbRequestReadyState\":[],\"IdbTransaction\":[\"EventTarget\"],\"IdbTransactionDurability\":[],\"IdbTransactionMode\":[],\"IdbTransactionOptions\":[],\"IdbVersionChangeEvent\":[\"Event\"],\"IdbVersionChangeEventInit\":[],\"IdleDeadline\":[],\"IdleRequestOptions\":[],\"IirFilterNode\":[\"AudioNode\",\"EventTarget\"],\"IirFilterOptions\":[],\"ImageBitmap\":[],\"ImageBitmapOptions\":[],\"ImageBitmapRenderingContext\":[],\"ImageCapture\":[],\"ImageCaptureError\":[],\"ImageCaptureErrorEvent\":[\"Event\"],\"ImageCaptureErrorEventInit\":[],\"ImageData\":[],\"ImageDecodeOptions\":[],\"ImageDecodeResult\":[],\"ImageDecoder\":[],\"ImageDecoderInit\":[],\"ImageEncodeOptions\":[],\"ImageOrientation\":[],\"ImageTrack\":[\"EventTarget\"],\"ImageTrackList\":[],\"InputDeviceInfo\":[\"MediaDeviceInfo\"],\"InputEvent\":[\"Event\",\"UiEvent\"],\"InputEventInit\":[],\"IntersectionObserver\":[],\"IntersectionObserverEntry\":[],\"IntersectionObserverEntryInit\":[],\"IntersectionObserverInit\":[],\"IntlUtils\":[],\"IsInputPendingOptions\":[],\"IterableKeyAndValueResult\":[],\"IterableKeyOrValueResult\":[],\"IterationCompositeOperation\":[],\"JsonWebKey\":[],\"KeyAlgorithm\":[],\"KeyEvent\":[],\"KeyFrameRequestEvent\":[\"Event\"],\"KeyIdsInitData\":[],\"KeyboardEvent\":[\"Event\",\"UiEvent\"],\"KeyboardEventInit\":[],\"KeyframeAnimationOptions\":[],\"KeyframeEffect\":[\"AnimationEffect\"],\"KeyframeEffectOptions\":[],\"L10nElement\":[],\"L10nValue\":[],\"LargeBlobSupport\":[],\"LatencyMode\":[],\"LifecycleCallbacks\":[],\"LineAlignSetting\":[],\"ListBoxObject\":[],\"LocalMediaStream\":[\"EventTarget\",\"MediaStream\"],\"LocaleInfo\":[],\"Location\":[],\"Lock\":[],\"LockInfo\":[],\"LockManager\":[],\"LockManagerSnapshot\":[],\"LockMode\":[],\"LockOptions\":[],\"MathMlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"MediaCapabilities\":[],\"MediaCapabilitiesInfo\":[],\"MediaConfiguration\":[],\"MediaDecodingConfiguration\":[],\"MediaDecodingType\":[],\"MediaDeviceInfo\":[],\"MediaDeviceKind\":[],\"MediaDevices\":[\"EventTarget\"],\"MediaElementAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaElementAudioSourceOptions\":[],\"MediaEncodingConfiguration\":[],\"MediaEncodingType\":[],\"MediaEncryptedEvent\":[\"Event\"],\"MediaError\":[],\"MediaImage\":[],\"MediaKeyError\":[\"Event\"],\"MediaKeyMessageEvent\":[\"Event\"],\"MediaKeyMessageEventInit\":[],\"MediaKeyMessageType\":[],\"MediaKeyNeededEventInit\":[],\"MediaKeySession\":[\"EventTarget\"],\"MediaKeySessionType\":[],\"MediaKeyStatus\":[],\"MediaKeyStatusMap\":[],\"MediaKeySystemAccess\":[],\"MediaKeySystemConfiguration\":[],\"MediaKeySystemMediaCapability\":[],\"MediaKeySystemStatus\":[],\"MediaKeys\":[],\"MediaKeysPolicy\":[],\"MediaKeysRequirement\":[],\"MediaList\":[],\"MediaMetadata\":[],\"MediaMetadataInit\":[],\"MediaPositionState\":[],\"MediaQueryList\":[\"EventTarget\"],\"MediaQueryListEvent\":[\"Event\"],\"MediaQueryListEventInit\":[],\"MediaRecorder\":[\"EventTarget\"],\"MediaRecorderErrorEvent\":[\"Event\"],\"MediaRecorderErrorEventInit\":[],\"MediaRecorderOptions\":[],\"MediaSession\":[],\"MediaSessionAction\":[],\"MediaSessionActionDetails\":[],\"MediaSessionPlaybackState\":[],\"MediaSource\":[\"EventTarget\"],\"MediaSourceEndOfStreamError\":[],\"MediaSourceEnum\":[],\"MediaSourceReadyState\":[],\"MediaStream\":[\"EventTarget\"],\"MediaStreamAudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceOptions\":[],\"MediaStreamConstraints\":[],\"MediaStreamError\":[],\"MediaStreamEvent\":[\"Event\"],\"MediaStreamEventInit\":[],\"MediaStreamTrack\":[\"EventTarget\"],\"MediaStreamTrackEvent\":[\"Event\"],\"MediaStreamTrackEventInit\":[],\"MediaStreamTrackGenerator\":[\"EventTarget\",\"MediaStreamTrack\"],\"MediaStreamTrackGeneratorInit\":[],\"MediaStreamTrackProcessor\":[],\"MediaStreamTrackProcessorInit\":[],\"MediaStreamTrackState\":[],\"MediaTrackCapabilities\":[],\"MediaTrackConstraintSet\":[],\"MediaTrackConstraints\":[],\"MediaTrackSettings\":[],\"MediaTrackSupportedConstraints\":[],\"MemoryAttribution\":[],\"MemoryAttributionContainer\":[],\"MemoryBreakdownEntry\":[],\"MemoryMeasurement\":[],\"MessageChannel\":[],\"MessageEvent\":[\"Event\"],\"MessageEventInit\":[],\"MessagePort\":[\"EventTarget\"],\"MidiAccess\":[\"EventTarget\"],\"MidiConnectionEvent\":[\"Event\"],\"MidiConnectionEventInit\":[],\"MidiInput\":[\"EventTarget\",\"MidiPort\"],\"MidiInputMap\":[],\"MidiMessageEvent\":[\"Event\"],\"MidiMessageEventInit\":[],\"MidiOptions\":[],\"MidiOutput\":[\"EventTarget\",\"MidiPort\"],\"MidiOutputMap\":[],\"MidiPort\":[\"EventTarget\"],\"MidiPortConnectionState\":[],\"MidiPortDeviceState\":[],\"MidiPortType\":[],\"MimeType\":[],\"MimeTypeArray\":[],\"MouseEvent\":[\"Event\",\"UiEvent\"],\"MouseEventInit\":[],\"MouseScrollEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"MozDebug\":[],\"MutationEvent\":[\"Event\"],\"MutationObserver\":[],\"MutationObserverInit\":[],\"MutationObservingInfo\":[],\"MutationRecord\":[],\"NamedNodeMap\":[],\"NativeOsFileReadOptions\":[],\"NativeOsFileWriteAtomicOptions\":[],\"NavigationType\":[],\"Navigator\":[],\"NavigatorAutomationInformation\":[],\"NavigatorUaBrandVersion\":[],\"NavigatorUaData\":[],\"NetworkCommandOptions\":[],\"NetworkInformation\":[\"EventTarget\"],\"NetworkResultOptions\":[],\"Node\":[\"EventTarget\"],\"NodeFilter\":[],\"NodeIterator\":[],\"NodeList\":[],\"Notification\":[\"EventTarget\"],\"NotificationAction\":[],\"NotificationDirection\":[],\"NotificationEvent\":[\"Event\",\"ExtendableEvent\"],\"NotificationEventInit\":[],\"NotificationOptions\":[],\"NotificationPermission\":[],\"ObserverCallback\":[],\"OesElementIndexUint\":[],\"OesStandardDerivatives\":[],\"OesTextureFloat\":[],\"OesTextureFloatLinear\":[],\"OesTextureHalfFloat\":[],\"OesTextureHalfFloatLinear\":[],\"OesVertexArrayObject\":[],\"OfflineAudioCompletionEvent\":[\"Event\"],\"OfflineAudioCompletionEventInit\":[],\"OfflineAudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"OfflineAudioContextOptions\":[],\"OfflineResourceList\":[\"EventTarget\"],\"OffscreenCanvas\":[\"EventTarget\"],\"OffscreenCanvasRenderingContext2d\":[],\"OpenFilePickerOptions\":[],\"OpenWindowEventDetail\":[],\"OptionalEffectTiming\":[],\"OrientationLockType\":[],\"OrientationType\":[],\"OscillatorNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"OscillatorOptions\":[],\"OscillatorType\":[],\"OverSampleType\":[],\"OvrMultiview2\":[],\"PageTransitionEvent\":[\"Event\"],\"PageTransitionEventInit\":[],\"PaintRequest\":[],\"PaintRequestList\":[],\"PaintWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"PannerNode\":[\"AudioNode\",\"EventTarget\"],\"PannerOptions\":[],\"PanningModelType\":[],\"ParityType\":[],\"Path2d\":[],\"PaymentAddress\":[],\"PaymentComplete\":[],\"PaymentMethodChangeEvent\":[\"Event\",\"PaymentRequestUpdateEvent\"],\"PaymentMethodChangeEventInit\":[],\"PaymentRequestUpdateEvent\":[\"Event\"],\"PaymentRequestUpdateEventInit\":[],\"PaymentResponse\":[],\"Pbkdf2Params\":[],\"PcImplIceConnectionState\":[],\"PcImplIceGatheringState\":[],\"PcImplSignalingState\":[],\"PcObserverStateType\":[],\"Performance\":[\"EventTarget\"],\"PerformanceEntry\":[],\"PerformanceEntryEventInit\":[],\"PerformanceEntryFilterOptions\":[],\"PerformanceMark\":[\"PerformanceEntry\"],\"PerformanceMeasure\":[\"PerformanceEntry\"],\"PerformanceNavigation\":[],\"PerformanceNavigationTiming\":[\"PerformanceEntry\",\"PerformanceResourceTiming\"],\"PerformanceObserver\":[],\"PerformanceObserverEntryList\":[],\"PerformanceObserverInit\":[],\"PerformanceResourceTiming\":[\"PerformanceEntry\"],\"PerformanceServerTiming\":[],\"PerformanceTiming\":[],\"PeriodicWave\":[],\"PeriodicWaveConstraints\":[],\"PeriodicWaveOptions\":[],\"PermissionDescriptor\":[],\"PermissionName\":[],\"PermissionState\":[],\"PermissionStatus\":[\"EventTarget\"],\"Permissions\":[],\"PictureInPictureEvent\":[\"Event\"],\"PictureInPictureEventInit\":[],\"PictureInPictureWindow\":[\"EventTarget\"],\"PlaneLayout\":[],\"PlaybackDirection\":[],\"Plugin\":[],\"PluginArray\":[],\"PluginCrashedEventInit\":[],\"PointerEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"PointerEventInit\":[],\"PopStateEvent\":[\"Event\"],\"PopStateEventInit\":[],\"PopupBlockedEvent\":[\"Event\"],\"PopupBlockedEventInit\":[],\"Position\":[],\"PositionAlignSetting\":[],\"PositionError\":[],\"PositionOptions\":[],\"PremultiplyAlpha\":[],\"Presentation\":[],\"PresentationAvailability\":[\"EventTarget\"],\"PresentationConnection\":[\"EventTarget\"],\"PresentationConnectionAvailableEvent\":[\"Event\"],\"PresentationConnectionAvailableEventInit\":[],\"PresentationConnectionBinaryType\":[],\"PresentationConnectionCloseEvent\":[\"Event\"],\"PresentationConnectionCloseEventInit\":[],\"PresentationConnectionClosedReason\":[],\"PresentationConnectionList\":[\"EventTarget\"],\"PresentationConnectionState\":[],\"PresentationReceiver\":[],\"PresentationRequest\":[\"EventTarget\"],\"PresentationStyle\":[],\"ProcessingInstruction\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"ProfileTimelineLayerRect\":[],\"ProfileTimelineMarker\":[],\"ProfileTimelineMessagePortOperationType\":[],\"ProfileTimelineStackFrame\":[],\"ProfileTimelineWorkerOperationType\":[],\"ProgressEvent\":[\"Event\"],\"ProgressEventInit\":[],\"PromiseNativeHandler\":[],\"PromiseRejectionEvent\":[\"Event\"],\"PromiseRejectionEventInit\":[],\"PublicKeyCredential\":[\"Credential\"],\"PublicKeyCredentialCreationOptions\":[],\"PublicKeyCredentialCreationOptionsJson\":[],\"PublicKeyCredentialDescriptor\":[],\"PublicKeyCredentialDescriptorJson\":[],\"PublicKeyCredentialEntity\":[],\"PublicKeyCredentialHints\":[],\"PublicKeyCredentialParameters\":[],\"PublicKeyCredentialRequestOptions\":[],\"PublicKeyCredentialRequestOptionsJson\":[],\"PublicKeyCredentialRpEntity\":[],\"PublicKeyCredentialType\":[],\"PublicKeyCredentialUserEntity\":[],\"PublicKeyCredentialUserEntityJson\":[],\"PushEncryptionKeyName\":[],\"PushEvent\":[\"Event\",\"ExtendableEvent\"],\"PushEventInit\":[],\"PushManager\":[],\"PushMessageData\":[],\"PushPermissionState\":[],\"PushSubscription\":[],\"PushSubscriptionInit\":[],\"PushSubscriptionJson\":[],\"PushSubscriptionKeys\":[],\"PushSubscriptionOptions\":[],\"PushSubscriptionOptionsInit\":[],\"QueryOptions\":[],\"QueuingStrategy\":[],\"QueuingStrategyInit\":[],\"RadioNodeList\":[\"NodeList\"],\"Range\":[],\"RcwnPerfStats\":[],\"RcwnStatus\":[],\"ReadableByteStreamController\":[],\"ReadableStream\":[],\"ReadableStreamByobReader\":[],\"ReadableStreamByobRequest\":[],\"ReadableStreamDefaultController\":[],\"ReadableStreamDefaultReader\":[],\"ReadableStreamGetReaderOptions\":[],\"ReadableStreamIteratorOptions\":[],\"ReadableStreamReadResult\":[],\"ReadableStreamReaderMode\":[],\"ReadableStreamType\":[],\"ReadableWritablePair\":[],\"RecordingState\":[],\"ReferrerPolicy\":[],\"RegisterRequest\":[],\"RegisterResponse\":[],\"RegisteredKey\":[],\"RegistrationOptions\":[],\"RegistrationResponseJson\":[],\"Request\":[],\"RequestCache\":[],\"RequestCredentials\":[],\"RequestDestination\":[],\"RequestDeviceOptions\":[],\"RequestInit\":[],\"RequestMediaKeySystemAccessNotification\":[],\"RequestMode\":[],\"RequestRedirect\":[],\"ResidentKeyRequirement\":[],\"ResizeObserver\":[],\"ResizeObserverBoxOptions\":[],\"ResizeObserverEntry\":[],\"ResizeObserverOptions\":[],\"ResizeObserverSize\":[],\"ResizeQuality\":[],\"Response\":[],\"ResponseInit\":[],\"ResponseType\":[],\"RsaHashedImportParams\":[],\"RsaOaepParams\":[],\"RsaOtherPrimesInfo\":[],\"RsaPssParams\":[],\"RtcAnswerOptions\":[],\"RtcBundlePolicy\":[],\"RtcCertificate\":[],\"RtcCertificateExpiration\":[],\"RtcCodecStats\":[],\"RtcConfiguration\":[],\"RtcDataChannel\":[\"EventTarget\"],\"RtcDataChannelEvent\":[\"Event\"],\"RtcDataChannelEventInit\":[],\"RtcDataChannelInit\":[],\"RtcDataChannelState\":[],\"RtcDataChannelType\":[],\"RtcDegradationPreference\":[],\"RtcEncodedAudioFrame\":[],\"RtcEncodedAudioFrameMetadata\":[],\"RtcEncodedAudioFrameOptions\":[],\"RtcEncodedVideoFrame\":[],\"RtcEncodedVideoFrameMetadata\":[],\"RtcEncodedVideoFrameOptions\":[],\"RtcEncodedVideoFrameType\":[],\"RtcFecParameters\":[],\"RtcIceCandidate\":[],\"RtcIceCandidateInit\":[],\"RtcIceCandidatePairStats\":[],\"RtcIceCandidateStats\":[],\"RtcIceComponentStats\":[],\"RtcIceConnectionState\":[],\"RtcIceCredentialType\":[],\"RtcIceGatheringState\":[],\"RtcIceServer\":[],\"RtcIceTransportPolicy\":[],\"RtcIdentityAssertion\":[],\"RtcIdentityAssertionResult\":[],\"RtcIdentityProvider\":[],\"RtcIdentityProviderDetails\":[],\"RtcIdentityProviderOptions\":[],\"RtcIdentityProviderRegistrar\":[],\"RtcIdentityValidationResult\":[],\"RtcInboundRtpStreamStats\":[],\"RtcMediaStreamStats\":[],\"RtcMediaStreamTrackStats\":[],\"RtcOfferAnswerOptions\":[],\"RtcOfferOptions\":[],\"RtcOutboundRtpStreamStats\":[],\"RtcPeerConnection\":[\"EventTarget\"],\"RtcPeerConnectionIceErrorEvent\":[\"Event\"],\"RtcPeerConnectionIceEvent\":[\"Event\"],\"RtcPeerConnectionIceEventInit\":[],\"RtcPeerConnectionState\":[],\"RtcPriorityType\":[],\"RtcRtcpParameters\":[],\"RtcRtpCapabilities\":[],\"RtcRtpCodecCapability\":[],\"RtcRtpCodecParameters\":[],\"RtcRtpContributingSource\":[],\"RtcRtpEncodingParameters\":[],\"RtcRtpHeaderExtensionCapability\":[],\"RtcRtpHeaderExtensionParameters\":[],\"RtcRtpParameters\":[],\"RtcRtpReceiver\":[],\"RtcRtpScriptTransform\":[],\"RtcRtpScriptTransformer\":[\"EventTarget\"],\"RtcRtpSender\":[],\"RtcRtpSourceEntry\":[],\"RtcRtpSourceEntryType\":[],\"RtcRtpSynchronizationSource\":[],\"RtcRtpTransceiver\":[],\"RtcRtpTransceiverDirection\":[],\"RtcRtpTransceiverInit\":[],\"RtcRtxParameters\":[],\"RtcSdpType\":[],\"RtcSessionDescription\":[],\"RtcSessionDescriptionInit\":[],\"RtcSignalingState\":[],\"RtcStats\":[],\"RtcStatsIceCandidatePairState\":[],\"RtcStatsIceCandidateType\":[],\"RtcStatsReport\":[],\"RtcStatsReportInternal\":[],\"RtcStatsType\":[],\"RtcTrackEvent\":[\"Event\"],\"RtcTrackEventInit\":[],\"RtcTransformEvent\":[\"Event\"],\"RtcTransportStats\":[],\"RtcdtmfSender\":[\"EventTarget\"],\"RtcdtmfToneChangeEvent\":[\"Event\"],\"RtcdtmfToneChangeEventInit\":[],\"RtcrtpContributingSourceStats\":[],\"RtcrtpStreamStats\":[],\"SFrameTransform\":[\"EventTarget\"],\"SFrameTransformErrorEvent\":[\"Event\"],\"SFrameTransformErrorEventInit\":[],\"SFrameTransformErrorEventType\":[],\"SFrameTransformOptions\":[],\"SFrameTransformRole\":[],\"SaveFilePickerOptions\":[],\"Scheduler\":[],\"SchedulerPostTaskOptions\":[],\"Scheduling\":[],\"Screen\":[\"EventTarget\"],\"ScreenColorGamut\":[],\"ScreenLuminance\":[],\"ScreenOrientation\":[\"EventTarget\"],\"ScriptProcessorNode\":[\"AudioNode\",\"EventTarget\"],\"ScrollAreaEvent\":[\"Event\",\"UiEvent\"],\"ScrollBehavior\":[],\"ScrollBoxObject\":[],\"ScrollIntoViewOptions\":[],\"ScrollLogicalPosition\":[],\"ScrollOptions\":[],\"ScrollRestoration\":[],\"ScrollSetting\":[],\"ScrollState\":[],\"ScrollToOptions\":[],\"ScrollViewChangeEventInit\":[],\"SecurityPolicyViolationEvent\":[\"Event\"],\"SecurityPolicyViolationEventDisposition\":[],\"SecurityPolicyViolationEventInit\":[],\"Selection\":[],\"SelectionMode\":[],\"Serial\":[\"EventTarget\"],\"SerialInputSignals\":[],\"SerialOptions\":[],\"SerialOutputSignals\":[],\"SerialPort\":[\"EventTarget\"],\"SerialPortFilter\":[],\"SerialPortInfo\":[],\"SerialPortRequestOptions\":[],\"ServerSocketOptions\":[],\"ServiceWorker\":[\"EventTarget\"],\"ServiceWorkerContainer\":[\"EventTarget\"],\"ServiceWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"ServiceWorkerRegistration\":[\"EventTarget\"],\"ServiceWorkerState\":[],\"ServiceWorkerUpdateViaCache\":[],\"ShadowRoot\":[\"DocumentFragment\",\"EventTarget\",\"Node\"],\"ShadowRootInit\":[],\"ShadowRootMode\":[],\"ShareData\":[],\"SharedWorker\":[\"EventTarget\"],\"SharedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"SignResponse\":[],\"SocketElement\":[],\"SocketOptions\":[],\"SocketReadyState\":[],\"SocketsDict\":[],\"SourceBuffer\":[\"EventTarget\"],\"SourceBufferAppendMode\":[],\"SourceBufferList\":[\"EventTarget\"],\"SpeechGrammar\":[],\"SpeechGrammarList\":[],\"SpeechRecognition\":[\"EventTarget\"],\"SpeechRecognitionAlternative\":[],\"SpeechRecognitionError\":[\"Event\"],\"SpeechRecognitionErrorCode\":[],\"SpeechRecognitionErrorInit\":[],\"SpeechRecognitionEvent\":[\"Event\"],\"SpeechRecognitionEventInit\":[],\"SpeechRecognitionResult\":[],\"SpeechRecognitionResultList\":[],\"SpeechSynthesis\":[\"EventTarget\"],\"SpeechSynthesisErrorCode\":[],\"SpeechSynthesisErrorEvent\":[\"Event\",\"SpeechSynthesisEvent\"],\"SpeechSynthesisErrorEventInit\":[],\"SpeechSynthesisEvent\":[\"Event\"],\"SpeechSynthesisEventInit\":[],\"SpeechSynthesisUtterance\":[\"EventTarget\"],\"SpeechSynthesisVoice\":[],\"StereoPannerNode\":[\"AudioNode\",\"EventTarget\"],\"StereoPannerOptions\":[],\"Storage\":[],\"StorageEstimate\":[],\"StorageEvent\":[\"Event\"],\"StorageEventInit\":[],\"StorageManager\":[],\"StorageType\":[],\"StreamPipeOptions\":[],\"StyleRuleChangeEventInit\":[],\"StyleSheet\":[],\"StyleSheetApplicableStateChangeEventInit\":[],\"StyleSheetChangeEventInit\":[],\"StyleSheetList\":[],\"SubmitEvent\":[\"Event\"],\"SubmitEventInit\":[],\"SubtleCrypto\":[],\"SupportedType\":[],\"SvcOutputMetadata\":[],\"SvgAngle\":[],\"SvgAnimateElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateMotionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateTransformElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimatedAngle\":[],\"SvgAnimatedBoolean\":[],\"SvgAnimatedEnumeration\":[],\"SvgAnimatedInteger\":[],\"SvgAnimatedLength\":[],\"SvgAnimatedLengthList\":[],\"SvgAnimatedNumber\":[],\"SvgAnimatedNumberList\":[],\"SvgAnimatedPreserveAspectRatio\":[],\"SvgAnimatedRect\":[],\"SvgAnimatedString\":[],\"SvgAnimatedTransformList\":[],\"SvgAnimationElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgBoundingBoxOptions\":[],\"SvgCircleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgClipPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgComponentTransferFunctionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgDefsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgDescElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgElement\":[\"Element\",\"EventTarget\",\"Node\"],\"SvgEllipseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgFilterElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgForeignObjectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGeometryElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgGraphicsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgLength\":[],\"SvgLengthList\":[],\"SvgLineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgLinearGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgMarkerElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMaskElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMatrix\":[],\"SvgMetadataElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgNumber\":[],\"SvgNumberList\":[],\"SvgPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPathSeg\":[],\"SvgPathSegArcAbs\":[\"SvgPathSeg\"],\"SvgPathSegArcRel\":[\"SvgPathSeg\"],\"SvgPathSegClosePath\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalRel\":[\"SvgPathSeg\"],\"SvgPathSegList\":[],\"SvgPathSegMovetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegMovetoRel\":[\"SvgPathSeg\"],\"SvgPatternElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgPoint\":[],\"SvgPointList\":[],\"SvgPolygonElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPolylineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPreserveAspectRatio\":[],\"SvgRadialGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgRect\":[],\"SvgRectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgScriptElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgStopElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgStringList\":[],\"SvgStyleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSwitchElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgSymbolElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTextContentElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgTextElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"SvgTextPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTextPositioningElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTitleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTransform\":[],\"SvgTransformList\":[],\"SvgUnitTypes\":[],\"SvgUseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgViewElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgZoomAndPan\":[],\"SvgaElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgfeBlendElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeColorMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeComponentTransferElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeCompositeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeConvolveMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDiffuseLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDisplacementMapElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDistantLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDropShadowElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFloodElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFuncAElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncBElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncGElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncRElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeGaussianBlurElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeNodeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMorphologyElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeOffsetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfePointLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpecularLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpotLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTileElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTurbulenceElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvggElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgmPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgsvgElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgtSpanElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"TaskController\":[\"AbortController\"],\"TaskControllerInit\":[],\"TaskPriority\":[],\"TaskPriorityChangeEvent\":[\"Event\"],\"TaskPriorityChangeEventInit\":[],\"TaskSignal\":[\"AbortSignal\",\"EventTarget\"],\"TaskSignalAnyInit\":[],\"TcpReadyState\":[],\"TcpServerSocket\":[\"EventTarget\"],\"TcpServerSocketEvent\":[\"Event\"],\"TcpServerSocketEventInit\":[],\"TcpSocket\":[\"EventTarget\"],\"TcpSocketBinaryType\":[],\"TcpSocketErrorEvent\":[\"Event\"],\"TcpSocketErrorEventInit\":[],\"TcpSocketEvent\":[\"Event\"],\"TcpSocketEventInit\":[],\"Text\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"TextDecodeOptions\":[],\"TextDecoder\":[],\"TextDecoderOptions\":[],\"TextEncoder\":[],\"TextMetrics\":[],\"TextTrack\":[\"EventTarget\"],\"TextTrackCue\":[\"EventTarget\"],\"TextTrackCueList\":[],\"TextTrackKind\":[],\"TextTrackList\":[\"EventTarget\"],\"TextTrackMode\":[],\"TimeEvent\":[\"Event\"],\"TimeRanges\":[],\"ToggleEvent\":[\"Event\"],\"ToggleEventInit\":[],\"TokenBinding\":[],\"TokenBindingStatus\":[],\"Touch\":[],\"TouchEvent\":[\"Event\",\"UiEvent\"],\"TouchEventInit\":[],\"TouchInit\":[],\"TouchList\":[],\"TrackEvent\":[\"Event\"],\"TrackEventInit\":[],\"TransformStream\":[],\"TransformStreamDefaultController\":[],\"Transformer\":[],\"TransitionEvent\":[\"Event\"],\"TransitionEventInit\":[],\"Transport\":[],\"TreeBoxObject\":[],\"TreeCellInfo\":[],\"TreeView\":[],\"TreeWalker\":[],\"U2f\":[],\"U2fClientData\":[],\"ULongRange\":[],\"UaDataValues\":[],\"UaLowEntropyJson\":[],\"UdpMessageEventInit\":[],\"UdpOptions\":[],\"UiEvent\":[\"Event\"],\"UiEventInit\":[],\"UnderlyingSink\":[],\"UnderlyingSource\":[],\"Url\":[],\"UrlSearchParams\":[],\"Usb\":[\"EventTarget\"],\"UsbAlternateInterface\":[],\"UsbConfiguration\":[],\"UsbConnectionEvent\":[\"Event\"],\"UsbConnectionEventInit\":[],\"UsbControlTransferParameters\":[],\"UsbDevice\":[],\"UsbDeviceFilter\":[],\"UsbDeviceRequestOptions\":[],\"UsbDirection\":[],\"UsbEndpoint\":[],\"UsbEndpointType\":[],\"UsbInTransferResult\":[],\"UsbInterface\":[],\"UsbIsochronousInTransferPacket\":[],\"UsbIsochronousInTransferResult\":[],\"UsbIsochronousOutTransferPacket\":[],\"UsbIsochronousOutTransferResult\":[],\"UsbOutTransferResult\":[],\"UsbPermissionDescriptor\":[],\"UsbPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"UsbPermissionStorage\":[],\"UsbRecipient\":[],\"UsbRequestType\":[],\"UsbTransferStatus\":[],\"UserActivation\":[],\"UserProximityEvent\":[\"Event\"],\"UserProximityEventInit\":[],\"UserVerificationRequirement\":[],\"ValidityState\":[],\"ValueEvent\":[\"Event\"],\"ValueEventInit\":[],\"VideoColorPrimaries\":[],\"VideoColorSpace\":[],\"VideoColorSpaceInit\":[],\"VideoConfiguration\":[],\"VideoDecoder\":[],\"VideoDecoderConfig\":[],\"VideoDecoderInit\":[],\"VideoDecoderSupport\":[],\"VideoEncoder\":[],\"VideoEncoderConfig\":[],\"VideoEncoderEncodeOptions\":[],\"VideoEncoderInit\":[],\"VideoEncoderSupport\":[],\"VideoFacingModeEnum\":[],\"VideoFrame\":[],\"VideoFrameBufferInit\":[],\"VideoFrameCopyToOptions\":[],\"VideoFrameInit\":[],\"VideoMatrixCoefficients\":[],\"VideoPixelFormat\":[],\"VideoPlaybackQuality\":[],\"VideoStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"VideoTrack\":[],\"VideoTrackList\":[\"EventTarget\"],\"VideoTransferCharacteristics\":[],\"ViewTransition\":[],\"VisibilityState\":[],\"VisualViewport\":[\"EventTarget\"],\"VoidCallback\":[],\"VrDisplay\":[\"EventTarget\"],\"VrDisplayCapabilities\":[],\"VrEye\":[],\"VrEyeParameters\":[],\"VrFieldOfView\":[],\"VrFrameData\":[],\"VrLayer\":[],\"VrMockController\":[],\"VrMockDisplay\":[],\"VrPose\":[],\"VrServiceTest\":[],\"VrStageParameters\":[],\"VrSubmitFrameResult\":[],\"VttCue\":[\"EventTarget\",\"TextTrackCue\"],\"VttRegion\":[],\"WakeLock\":[],\"WakeLockSentinel\":[\"EventTarget\"],\"WakeLockType\":[],\"WatchAdvertisementsOptions\":[],\"WaveShaperNode\":[\"AudioNode\",\"EventTarget\"],\"WaveShaperOptions\":[],\"WebGl2RenderingContext\":[],\"WebGlActiveInfo\":[],\"WebGlBuffer\":[],\"WebGlContextAttributes\":[],\"WebGlContextEvent\":[\"Event\"],\"WebGlContextEventInit\":[],\"WebGlFramebuffer\":[],\"WebGlPowerPreference\":[],\"WebGlProgram\":[],\"WebGlQuery\":[],\"WebGlRenderbuffer\":[],\"WebGlRenderingContext\":[],\"WebGlSampler\":[],\"WebGlShader\":[],\"WebGlShaderPrecisionFormat\":[],\"WebGlSync\":[],\"WebGlTexture\":[],\"WebGlTransformFeedback\":[],\"WebGlUniformLocation\":[],\"WebGlVertexArrayObject\":[],\"WebKitCssMatrix\":[\"DomMatrix\",\"DomMatrixReadOnly\"],\"WebSocket\":[\"EventTarget\"],\"WebSocketDict\":[],\"WebSocketElement\":[],\"WebTransport\":[],\"WebTransportBidirectionalStream\":[],\"WebTransportCloseInfo\":[],\"WebTransportCongestionControl\":[],\"WebTransportDatagramDuplexStream\":[],\"WebTransportDatagramStats\":[],\"WebTransportError\":[\"DomException\"],\"WebTransportErrorOptions\":[],\"WebTransportErrorSource\":[],\"WebTransportHash\":[],\"WebTransportOptions\":[],\"WebTransportReceiveStream\":[\"ReadableStream\"],\"WebTransportReceiveStreamStats\":[],\"WebTransportReliabilityMode\":[],\"WebTransportSendStream\":[\"WritableStream\"],\"WebTransportSendStreamOptions\":[],\"WebTransportSendStreamStats\":[],\"WebTransportStats\":[],\"WebglColorBufferFloat\":[],\"WebglCompressedTextureAstc\":[],\"WebglCompressedTextureAtc\":[],\"WebglCompressedTextureEtc\":[],\"WebglCompressedTextureEtc1\":[],\"WebglCompressedTexturePvrtc\":[],\"WebglCompressedTextureS3tc\":[],\"WebglCompressedTextureS3tcSrgb\":[],\"WebglDebugRendererInfo\":[],\"WebglDebugShaders\":[],\"WebglDepthTexture\":[],\"WebglDrawBuffers\":[],\"WebglLoseContext\":[],\"WebglMultiDraw\":[],\"WellKnownDirectory\":[],\"WgslLanguageFeatures\":[],\"WheelEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"WheelEventInit\":[],\"WidevineCdmManifest\":[],\"Window\":[\"EventTarget\"],\"WindowClient\":[\"Client\"],\"Worker\":[\"EventTarget\"],\"WorkerDebuggerGlobalScope\":[\"EventTarget\"],\"WorkerGlobalScope\":[\"EventTarget\"],\"WorkerLocation\":[],\"WorkerNavigator\":[],\"WorkerOptions\":[],\"WorkerType\":[],\"Worklet\":[],\"WorkletGlobalScope\":[],\"WorkletOptions\":[],\"WritableStream\":[],\"WritableStreamDefaultController\":[],\"WritableStreamDefaultWriter\":[],\"WriteCommandType\":[],\"WriteParams\":[],\"XPathExpression\":[],\"XPathNsResolver\":[],\"XPathResult\":[],\"XmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"XmlHttpRequest\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlHttpRequestEventTarget\":[\"EventTarget\"],\"XmlHttpRequestResponseType\":[],\"XmlHttpRequestUpload\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlSerializer\":[],\"XrBoundedReferenceSpace\":[\"EventTarget\",\"XrReferenceSpace\",\"XrSpace\"],\"XrEye\":[],\"XrFrame\":[],\"XrHand\":[],\"XrHandJoint\":[],\"XrHandedness\":[],\"XrInputSource\":[],\"XrInputSourceArray\":[],\"XrInputSourceEvent\":[\"Event\"],\"XrInputSourceEventInit\":[],\"XrInputSourcesChangeEvent\":[\"Event\"],\"XrInputSourcesChangeEventInit\":[],\"XrJointPose\":[\"XrPose\"],\"XrJointSpace\":[\"EventTarget\",\"XrSpace\"],\"XrLayer\":[\"EventTarget\"],\"XrPermissionDescriptor\":[],\"XrPermissionStatus\":[\"EventTarget\",\"PermissionStatus\"],\"XrPose\":[],\"XrReferenceSpace\":[\"EventTarget\",\"XrSpace\"],\"XrReferenceSpaceEvent\":[\"Event\"],\"XrReferenceSpaceEventInit\":[],\"XrReferenceSpaceType\":[],\"XrRenderState\":[],\"XrRenderStateInit\":[],\"XrRigidTransform\":[],\"XrSession\":[\"EventTarget\"],\"XrSessionEvent\":[\"Event\"],\"XrSessionEventInit\":[],\"XrSessionInit\":[],\"XrSessionMode\":[],\"XrSessionSupportedPermissionDescriptor\":[],\"XrSpace\":[\"EventTarget\"],\"XrSystem\":[\"EventTarget\"],\"XrTargetRayMode\":[],\"XrView\":[],\"XrViewerPose\":[\"XrPose\"],\"XrViewport\":[],\"XrVisibilityState\":[],\"XrWebGlLayer\":[\"EventTarget\",\"XrLayer\"],\"XrWebGlLayerInit\":[],\"XsltProcessor\":[],\"console\":[],\"css\":[],\"default\":[\"std\"],\"gpu_buffer_usage\":[],\"gpu_color_write\":[],\"gpu_map_mode\":[],\"gpu_shader_stage\":[],\"gpu_texture_usage\":[],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\"]}}", "web-time_1.1.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_feature = \\\"atomics\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_feature = \\\"atomics\\\"))\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"},{\"name\":\"js-sys\",\"req\":\"^0.3.20\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"macro\"],\"kind\":\"dev\",\"name\":\"pollster\",\"req\":\"^0.3\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"^0.2.70\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-futures\",\"req\":\"^0.4\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"},{\"features\":[\"WorkerGlobalScope\"],\"kind\":\"dev\",\"name\":\"web-sys\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_feature = \\\"atomics\\\"))\"},{\"features\":[\"CssStyleDeclaration\",\"Document\",\"Element\",\"HtmlTableElement\",\"HtmlTableRowElement\",\"Performance\",\"Window\"],\"kind\":\"dev\",\"name\":\"web-sys\",\"req\":\"^0.3\",\"target\":\"cfg(target_family = \\\"wasm\\\")\"}],\"features\":{\"serde\":[\"dep:serde\"]}}", "webpki-root-certs_1.0.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"default_features\":false,\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"ring\",\"req\":\"^0.17.0\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17.0\"}],\"features\":{}}", "webpki-roots_0.26.11": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"parent\",\"package\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"ring\",\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.102\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"yasna\",\"req\":\"^0.5.2\"}],\"features\":{}}", "webpki-roots_1.0.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"default_features\":false,\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"ring\",\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"yasna\",\"req\":\"^0.5.2\"}],\"features\":{}}", + "webpki-roots_1.0.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"aws-lc-rs\",\"req\":\"^1.15.2\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"default_features\":false,\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.18\"},{\"kind\":\"dev\",\"name\":\"yasna\",\"req\":\"^0.6\"}],\"features\":{}}", "which_8.0.2": "{\"dependencies\":[{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(any(unix, target_os = \\\"wasi\\\", target_os = \\\"redox\\\"))\"},{\"name\":\"regex\",\"optional\":true,\"req\":\"^1.10.2\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.9.0\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.40\"}],\"features\":{\"default\":[\"real-sys\"],\"real-sys\":[\"dep:libc\"],\"regex\":[\"dep:regex\"],\"tracing\":[\"dep:tracing\"]}}", "widestring_1.2.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"debugger_test\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"debugger_test_parser\",\"req\":\"^0.1\"},{\"features\":[\"Win32_System_Diagnostics_Debug\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.59\"}],\"features\":{\"alloc\":[],\"debugger_visualizer\":[\"alloc\"],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "winapi-util_0.1.11": "{\"dependencies\":[{\"features\":[\"Win32_Foundation\",\"Win32_Storage_FileSystem\",\"Win32_System_Console\",\"Win32_System_SystemInformation\"],\"name\":\"windows-sys\",\"req\":\">=0.48.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{}}", - "wincode-derive_0.4.5": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.21.3\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"features\":[\"visit-mut\",\"visit\"],\"name\":\"syn\",\"req\":\"^2.0.117\"}],\"features\":{}}", - "wincode_0.5.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"default_features\":false,\"name\":\"bv\",\"optional\":true,\"req\":\"^0.11.1\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bv\",\"req\":\"^0.11.1\"},{\"default_features\":false,\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.11.1\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"name\":\"ecow\",\"optional\":true,\"req\":\"^0.2.6\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"ecow\",\"req\":\"^0.2.6\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.13.1\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"indexmap\",\"req\":\"^2.13.1\"},{\"name\":\"pastey\",\"req\":\"^0.2.1\"},{\"kind\":\"build\",\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.11.0\"},{\"kind\":\"dev\",\"name\":\"proptest-derive\",\"req\":\"^0.8.0\"},{\"kind\":\"build\",\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.2\"},{\"features\":[\"derive\",\"rc\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.227\"},{\"default_features\":false,\"features\":[\"const_generics\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.15.1\"},{\"default_features\":false,\"features\":[\"const_generics\",\"serde\"],\"kind\":\"dev\",\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"default_features\":false,\"name\":\"solana-short-vec\",\"optional\":true,\"req\":\"^3.2.0\"},{\"kind\":\"dev\",\"name\":\"solana-short-vec\",\"req\":\"^3.2.0\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"default_features\":false,\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.23.0\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.23.0\"},{\"name\":\"wincode-derive\",\"optional\":true,\"req\":\"^0.4.5\"}],\"features\":{\"alloc\":[],\"bv\":[\"std\",\"dep:bv\"],\"bytes\":[\"alloc\",\"dep:bytes\"],\"bytes-extra-platforms\":[\"bytes\",\"bytes/extra-platforms\"],\"default\":[\"std\"],\"derive\":[\"dep:wincode-derive\"],\"ecow\":[\"alloc\",\"dep:ecow\"],\"indexmap\":[\"alloc\",\"dep:indexmap\"],\"smallvec\":[\"alloc\",\"dep:smallvec\"],\"solana-short-vec\":[\"dep:solana-short-vec\"],\"std\":[\"alloc\",\"thiserror/std\"],\"uuid\":[\"dep:uuid\"],\"uuid-serde-compat\":[\"uuid\"]}}", + "wincode-derive_0.4.6": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.23.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"features\":[\"visit-mut\",\"visit\"],\"name\":\"syn\",\"req\":\"^2.0.117\"}],\"features\":{}}", + "wincode_0.5.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"default_features\":false,\"name\":\"bv\",\"optional\":true,\"req\":\"^0.11.1\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"bv\",\"req\":\"^0.11.1\"},{\"default_features\":false,\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.11.1\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"name\":\"ecow\",\"optional\":true,\"req\":\"^0.2.6\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"ecow\",\"req\":\"^0.2.6\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.13.1\"},{\"default_features\":false,\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"indexmap\",\"req\":\"^2.13.1\"},{\"name\":\"pastey\",\"req\":\"^0.2.2\"},{\"kind\":\"build\",\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.11.0\"},{\"kind\":\"dev\",\"name\":\"proptest-derive\",\"req\":\"^0.8.0\"},{\"kind\":\"build\",\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.2\"},{\"features\":[\"derive\",\"rc\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.227\"},{\"default_features\":false,\"features\":[\"const_generics\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.15.1\"},{\"default_features\":false,\"features\":[\"const_generics\",\"serde\"],\"kind\":\"dev\",\"name\":\"smallvec\",\"req\":\"^1.15.1\"},{\"default_features\":false,\"name\":\"solana-short-vec\",\"optional\":true,\"req\":\"^3.2.1\"},{\"kind\":\"dev\",\"name\":\"solana-short-vec\",\"req\":\"^3.2.1\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2.0.18\"},{\"default_features\":false,\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.23.1\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.23.1\"},{\"name\":\"wincode-derive\",\"optional\":true,\"req\":\"^0.4.6\"}],\"features\":{\"alloc\":[],\"bv\":[\"std\",\"dep:bv\"],\"bytes\":[\"alloc\",\"dep:bytes\"],\"bytes-extra-platforms\":[\"bytes\",\"bytes/extra-platforms\"],\"default\":[\"std\"],\"derive\":[\"dep:wincode-derive\"],\"ecow\":[\"alloc\",\"dep:ecow\"],\"indexmap\":[\"alloc\",\"dep:indexmap\"],\"smallvec\":[\"alloc\",\"dep:smallvec\"],\"solana-short-vec\":[\"dep:solana-short-vec\"],\"std\":[\"alloc\",\"thiserror/std\"],\"uuid\":[\"dep:uuid\"],\"uuid-serde-compat\":[\"uuid\"]}}", "windows-core_0.62.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"windows-implement\",\"req\":\"^0.60.2\"},{\"default_features\":false,\"name\":\"windows-interface\",\"req\":\"^0.59.3\"},{\"default_features\":false,\"name\":\"windows-link\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"name\":\"windows-result\",\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"windows-strings\",\"req\":\"^0.5.1\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"windows-result/std\",\"windows-strings/std\"]}}", "windows-implement_0.60.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"parsing\",\"proc-macro\",\"printing\",\"full\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{}}", "windows-interface_0.59.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"parsing\",\"proc-macro\",\"printing\",\"full\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{}}", @@ -1422,7 +1360,9 @@ "yansi_1.0.1": "{\"dependencies\":[{\"name\":\"is-terminal\",\"optional\":true,\"req\":\"^0.4.11\"}],\"features\":{\"_nightly\":[],\"alloc\":[],\"default\":[\"std\"],\"detect-env\":[\"std\"],\"detect-tty\":[\"is-terminal\",\"std\"],\"hyperlink\":[\"std\"],\"std\":[\"alloc\"]}}", "yoke-derive_0.8.2": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.61\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"features\":[\"fold\"],\"name\":\"syn\",\"req\":\"^2.0.21\"},{\"name\":\"synstructure\",\"req\":\"^0.13.0\"}],\"features\":{}}", "yoke_0.8.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"req\":\"^1.2.0\"},{\"default_features\":false,\"name\":\"yoke-derive\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"zerofrom\",\"optional\":true,\"req\":\"^0.1.6\"}],\"features\":{\"alloc\":[\"stable_deref_trait/alloc\",\"zerofrom/alloc\"],\"default\":[\"alloc\",\"zerofrom\"],\"derive\":[\"dep:yoke-derive\",\"zerofrom/derive\"],\"serde\":[],\"zerofrom\":[\"dep:zerofrom\"]}}", + "zerocopy-derive_0.8.48": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"dissimilar\",\"req\":\"^1.0.9\"},{\"kind\":\"dev\",\"name\":\"prettyplease\",\"req\":\"=0.2.17\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.1\"},{\"name\":\"quote\",\"req\":\"^1.0.40\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.46\"},{\"features\":[\"visit\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.46\"}],\"features\":{}}", "zerocopy-derive_0.8.50": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"dissimilar\",\"req\":\"^1.0.9\"},{\"kind\":\"dev\",\"name\":\"prettyplease\",\"req\":\"=0.2.17\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.1\"},{\"name\":\"quote\",\"req\":\"^1.0.40\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.46\"},{\"features\":[\"visit\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.46\"}],\"features\":{}}", + "zerocopy_0.8.48": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"elain\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"zerocopy-derive\",\"req\":\"=0.8.48\",\"target\":\"cfg(any())\"},{\"name\":\"zerocopy-derive\",\"optional\":true,\"req\":\"=0.8.48\"},{\"kind\":\"dev\",\"name\":\"zerocopy-derive\",\"req\":\"=0.8.48\"}],\"features\":{\"__internal_use_only_features_that_work_on_stable\":[\"alloc\",\"derive\",\"simd\",\"std\"],\"alloc\":[],\"derive\":[\"zerocopy-derive\"],\"float-nightly\":[],\"simd\":[],\"simd-nightly\":[\"simd\"],\"std\":[\"alloc\"]}}", "zerocopy_0.8.50": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"elain\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"zerocopy-derive\",\"req\":\"=0.8.50\",\"target\":\"cfg(any())\"},{\"name\":\"zerocopy-derive\",\"optional\":true,\"req\":\"=0.8.50\"},{\"kind\":\"dev\",\"name\":\"zerocopy-derive\",\"req\":\"=0.8.50\"}],\"features\":{\"__internal_use_only_features_that_work_on_stable\":[\"alloc\",\"derive\",\"simd\",\"std\"],\"alloc\":[],\"derive\":[\"zerocopy-derive\"],\"float-nightly\":[],\"simd\":[],\"simd-nightly\":[\"simd\"],\"std\":[\"alloc\"]}}", "zerofrom-derive_0.1.7": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.61\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"features\":[\"fold\"],\"name\":\"syn\",\"req\":\"^2.0.21\"},{\"name\":\"synstructure\",\"req\":\"^0.13.0\"}],\"features\":{}}", "zerofrom_0.1.8": "{\"dependencies\":[{\"default_features\":false,\"name\":\"zerofrom-derive\",\"optional\":true,\"req\":\"^0.1.6\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"],\"derive\":[\"dep:zerofrom-derive\"]}}", @@ -1495,6 +1435,7 @@ "rust-std-1.92.0-powerpc64-unknown-linux-gnu.tar.xz": "2ce706afa4a46b6773340854de877fc63618a40e351298a4e3da8eb482619863", "rust-std-1.92.0-powerpc64le-unknown-linux-gnu.tar.xz": "eba59766c2d9805c0a1fc82fd723acbb36569e1bec1088c037bba84d965f70ba", "rust-std-1.92.0-powerpc64le-unknown-linux-musl.tar.xz": "8b515e18b6ac8f8d37ea3cabe644b7f571984333c3b4192b7f5877e79eae7893", + "rust-std-1.92.0-riscv32imac-unknown-none-elf.tar.xz": "5915223db6b8afa173f67eb4fe6f5aff2402351ed9abab1b370d0860be4af6c9", "rust-std-1.92.0-riscv32imc-unknown-none-elf.tar.xz": "e1c6968ce25ab78f2c5b5460691763a2d39cb71b01d6d54c208d4a8b735b0584", "rust-std-1.92.0-riscv64gc-unknown-linux-gnu.tar.xz": "8ee20dcf3b1063fa6069b3ce85e1fcf42794dfa783263314865cb53fff42d9e4", "rust-std-1.92.0-riscv64gc-unknown-linux-musl.tar.xz": "f20d822309900fd6c7230688694baf91e900154e44e6247feca49b7b7a203a57", @@ -1529,6 +1470,7 @@ "rustc-1.92.0-aarch64-apple-darwin.tar.xz": "15dee753c9217dff4cf45d734b29dc13ce6017d8a55fe34eed75022b39a63ff0", "rustc-1.92.0-aarch64-pc-windows-msvc.tar.xz": "07ba5606143de3bc916455714f67732fca05805591396a8190d5e88b8863eea3", "rustc-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "7c8706fad4c038b5eacab0092e15db54d2b365d5f3323ca046fe987f814e7826", + "rustc-1.92.0-src.tar.xz": "ebee170bfe4c4dfc59521a101de651e5534f4dae889756a5c97ca9ea40d0c307", "rustc-1.92.0-x86_64-apple-darwin.tar.xz": "0facbd5d2742c8e97c53d59c9b5b81db6088cfc285d9ecb99523a50d6765fc5c", "rustc-1.92.0-x86_64-pc-windows-msvc.tar.xz": "6aec5aba5384ce1041538e71ebebf671d82e29f4fe697bc7844626d94b0dbfe6", "rustc-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "78b2dd9c6b1fcd2621fa81c611cf5e2d6950690775038b585c64f364422886e0", diff --git a/README.md b/README.md index c9068c532..db4c80de9 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ NativeLink is trusted in production environments to reduce costs and developer i - Utilizes remote resources to offload computational burden from local machines - Ensures consistency with a uniform, controlled build environment -NativeLink seamlessly integrates with build tools that use the Remote Execution protocol, such as [Bazel](https://bazel.build), [Buck2](https://buck2.build), [Goma](https://chromium.googlesource.com/infra/goma/client/), and [Reclient](https://github.com/bazelbuild/reclient). CMake projects work too via [`recc`](https://buildgrid.gitlab.io/recc). See [Build CMake projects with NativeLink](https://nativelink.com/docs/rbe/cmake-recc). It supports Unix-based operating systems and Windows, ensuring broad compatibility across different development environments. +NativeLink seamlessly integrates with build tools that use the Remote Execution protocol, such as [Bazel](https://bazel.build), [Buck2](https://buck2.build), [Goma](https://chromium.googlesource.com/infra/goma/client/), and [Siso](https://chromium.googlesource.com/build/+/refs/heads/main/siso/README.md). CMake projects work too via [`recc`](https://buildgrid.gitlab.io/recc). See [Build CMake projects with NativeLink](https://docs.nativelink.com/getting-started/other-build-systems/cmake-recc). It supports Unix-based operating systems and Windows, ensuring broad compatibility across different development environments. ## 🚀 Quickstart @@ -112,6 +112,18 @@ it via the [next-gen nix installer](https://github.com/NixOS/experimental-nix-in > Executables built for MacOS are dynamically linked against libraries from Nix > and won't work on systems that don't have these libraries present. +> [!TIP] +> **Common setup gotchas for Nix on macOS / Linux:** +> * **Active shell environment**: If the installer finishes but your shell doesn't recognize `nix` commands, you need to either restart your terminal session or source the daemon profile manually: +> ```bash +> . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh +> ``` +> * **Enabling experimental features**: If you used the standard Nix installer and get an error saying `experimental Nix feature 'nix-command' is disabled`, enable them by creating or editing `~/.config/nix/nix.conf`: +> ```text +> experimental-features = nix-command flakes +> ``` +> * **Disk Space**: Unpacking and building compilers and dependencies requires significant storage. Make sure you have at least **15–20 GB of free space** on your system volume before running setup commands. + **Linux, MacOS, WSL2** ```bash @@ -133,7 +145,7 @@ Visit our [Contributing](https://github.com/tracemachina/nativelink/blob/main/CO ## 📜 License -Copyright 2020–2025 Trace Machina, Inc. +Copyright 2020–2026 Trace Machina, Inc. Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License. SPDX identifier: `FSL-1.1-Apache-2.0`. diff --git a/ci.bazelrc b/ci.bazelrc new file mode 100644 index 000000000..412c724cf --- /dev/null +++ b/ci.bazelrc @@ -0,0 +1,68 @@ +# Copyright 2022 The NativeLink Authors. All rights reserved. +# +# Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# See LICENSE file for details +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# NativeLink Cloud configuration for this repository's own CI. Everything here +# is opt-in via --config; plain local builds are unaffected. CI activates these +# groups through a generated user.bazelrc (see +# .github/actions/setup-nativelink-cloud), which injects the claim endpoints +# and the --remote_header/--bes_header credentials from repository secrets — +# neither endpoints nor secrets belong in this file. + +# --- Behavior groups (endpoint-free) --- + +# Remote cache + BES for lanes that still execute locally. Safe on any host. +common:nl-cache --remote_timeout=600 +common:nl-cache --remote_retries=5 +# Emit the optional BEP records that are most useful for invocation and target +# inspection. These flags are shared by the Bazel 8 and Bazel 9 CI lanes. +common:nl-cache --build_event_publish_all_actions +common:nl-cache --experimental_bep_target_summary +common:nl-cache --experimental_build_event_expand_filesets +common:nl-cache --experimental_run_bep_event_include_residue +common:nl-cache --bes_lifecycle_events +# CI must not report success before the backend has acknowledged the complete +# stream. `fully_async` may lose events, leave streams incomplete, and omit the +# final lifecycle events when a runner exits or an upload transiently fails. +common:nl-cache --bes_upload_mode=wait_for_upload_complete +common:nl-cache --build_event_upload_max_retries=8 + +# Main-branch mode: populate the shared cache. Only TraceMachina main-branch +# identities may hold a write-capable key; PR lanes instead get a plain +# --remote_upload_local_results=false line from the setup action. +common:nl-write --remote_upload_local_results=true +common:nl-write --remote_cache_async + +# Remote execution. Mirrors the staging-rbe config proven from a developer +# machine: hermetic LLVM plus downloaded Rust toolchains, so workers need no +# GCC/Rust/Nix. Combine only with an *-exec endpoint group, and only on +# x86_64 Linux hosts — macOS auto-applies conflicting LRE platforms from +# lre.bazelrc, which the setup action guards against. +common:nl-rbe --platforms=@llvm//platforms:linux_x86_64_gnu.2.28 +common:nl-rbe --host_platform=@llvm//platforms:linux_x86_64_gnu.2.28 +common:nl-rbe --extra_execution_platforms=@llvm//platforms:linux_x86_64_gnu.2.28 +common:nl-rbe --extra_toolchains=@rust_toolchains//:all +# The default musl interpreter is dynamically linked against the musl loader, +# which glibc-only worker images lack (genrule tools exit 127). +common:nl-rbe --@rules_python//python/config_settings:py_linux_libc=glibc +common:nl-rbe --jobs=200 +# --remote_download_toplevel (not minimal): keep intermediate output trees on +# the client so a CAS eviction mid-build is recoverable (the client can +# re-upload) instead of a fatal FAILED_PRECONDITION "not found in fast or slow +# store". Minimal keeps intermediates remote-only, which made eviction fatal. +common:nl-rbe --remote_download_toplevel +common:nl-rbe --remote_retries=8 +common:nl-rbe --experimental_remote_cache_eviction_retries=5 + +# Endpoints deliberately do not appear in this file: the setup action derives +# them from the claim-base repository secret at job time. diff --git a/cliff.toml b/cliff.toml index 46c513a3e..a6f29261f 100644 --- a/cliff.toml +++ b/cliff.toml @@ -68,6 +68,7 @@ commit_parsers = [ { message = "Account for block size in filesystem store for eviction purposes", group = "🐛 Bug Fixes" }, { message = "Add ONTAP S3 Store with existence cache", group = "⛰️ Features" }, { message = "Add OSFamily property in basic_cas.json", group = "📚 Documentation" }, + { message = "Add REAPI content-defined chunking", group = "⛰️ Features" }, { message = "Add configuration breakdown page", group = "📚 Documentation" }, { message = "Add rt-tokio feature to aws-sdk-s3", group = "🐛 Bug Fixes" }, { message = "Add trending badge", group = "⚙️ Miscellaneous" }, @@ -77,17 +78,23 @@ commit_parsers = [ { message = "Create directory for action", group = "⛰️ Features" }, { message = "De-dupe the fast-slow store", group = "🐛 Bug Fixes" }, { message = "Detect anonymous GCS auth and optionally quit", group = "⛰️ Features" }, + { message = "Disable Bazel lockfile in 8.7 compatibility lane", group = "🧪 Testing & CI" }, { message = "Don't retry permanent failures", group = "🐛 Bug Fixes" }, { message = "Draw a General Purpose Diagram", group = "📚 Documentation" }, { message = "Evict on touch failure", group = "🐛 Bug Fixes" }, { message = "Existence cache remove callbacks", group = "🐛 Bug Fixes" }, + { message = "Fix duplicate phrase in CONTRIBUTING.md", group = "📚 Documentation" }, { message = "Fix incorrect bazel version 6.4.0", group = "📚 Documentation" }, + { message = "Flush in detect_duplicate_upload", group = "🐛 Bug Fixes" }, { message = "GrpcStore now sends digest function from context", group = "🐛 Bug Fixes" }, { message = "Implement .* feature", group = "⛰️ Features" }, { message = "Implement `ClientStateManager` for `SimpleScheduler`", group = "⚙️ Miscellaneous" }, + { message = "Increase the attic retry time", group = "🧪 Testing & CI" }, { message = "Log failures to update actions", group = "⛰️ Features" }, { message = "Log on command complete", group = "⛰️ Features" }, { message = "Make the error on a size field clearer", group = "🐛 Bug Fixes" }, + { message = "Marcussorealheis extend zstd", group = "⛰️ Features" }, + { message = "Materialize directory-cache nodes concurrently on cold misses", group = "⛰️ Features" }, { message = "Migrate to callPackage syntax", group = "⚙️ Miscellaneous" }, { message = "Move Bytestream to array config", group = "⛰️ Features" }, { message = "Move `update_action_with_internal_error` into `StateManager`", group = "⚙️ Miscellaneous" }, @@ -96,6 +103,8 @@ commit_parsers = [ { message = "Remove nativelink-proto as build dependency", group = "🧪 Testing & CI" }, { message = "Retry GrpcStore get_part_ref", group = "⛰️ Features" }, { message = "Shard store weight scale distribution", group = "⛰️ Features" }, + { message = "Upgrade crossbeam-epoch and serial_test", group = "⬆️ Bumps & Version Updates" }, + { message = "Upgrade to Bazel 9.1.1 and 8.7.0", group = "⬆️ Bumps & Version Updates" }, { message = "Use mimalloc", group = "⛰️ Features" }, # Get all breaking changes first. @@ -137,6 +146,7 @@ commit_parsers = [ { message = "Merge branch", skip = true }, { message = "Prepare.+release", skip = true }, { message = "Release", skip = true }, + { message = "wtf", skip = true }, # Catch-all in miscellaneous { message = ".*", group = "⚙️ Miscellaneous" }, diff --git a/clippy.toml b/clippy.toml index 925f27f2b..2e3ed029d 100644 --- a/clippy.toml +++ b/clippy.toml @@ -14,4 +14,83 @@ disallowed-methods = [ { path = "tokio::task::spawn_blocking", reason = "use `nativelink-util::task::spawn_blocking` instead" }, { path = "tokio::task::spawn_local", reason = "use one of the `nativelink-util::task` functions instead" }, ] +# Started from the default at https://doc.rust-lang.org/clippy/lint_configuration.html#doc-valid-idents +doc-valid-idents = [ + "AccessKit", + "BibLaTeX", + "BibTeX", + "CamelCase", + "ClojureScript", + "CoAP", + "CoffeeScript", + "CoreFoundation", + "CoreGraphics", + "CoreText", + "DevOps", + "Direct2D", + "Direct3D", + "DirectWrite", + "DirectX", + "ECMAScript", + "EiB", + "FreeBSD", + "GHz", + "GPLv2", + "GPLv3", + "GiB", + "GitHub", + "GitLab", + "GraphQL", + "IPv4", + "IPv6", + "InfiniBand", + "JavaScript", + "KiB", + "LaTeX", + "MHz", + "MiB", + "MinGW", + "NaN", + "NaNs", + "NetApp", + "NetBSD", + "NixOS", + "OAuth", + "OCaml", + "OpenAL", + "OpenBSD", + "OpenDNS", + "OpenExr", + "OpenGL", + "OpenMP", + "OpenSSH", + "OpenSSL", + "OpenStreetMap", + "OpenTelemetry", + "OpenType", + "PiB", + "PostScript", + "PowerPC", + "PowerShell", + "PureScript", + "RoCE", + "THz", + "TeX", + "TensorFlow", + "TiB", + "TrueType", + "TypeScript", + "WebAssembly", + "WebGL", + "WebGL2", + "WebGPU", + "WebP", + "WebRTC", + "WebSocket", + "WebTransport", + "YCbCr", + "iOS", + "macOS", + "sRGB", +] msrv = "1.93.1" diff --git a/deploy/chromium-example/build_chromium_tests.sh b/deploy/chromium-example/build_chromium_tests.sh index 5faaabbda..1cb26d9e1 100755 --- a/deploy/chromium-example/build_chromium_tests.sh +++ b/deploy/chromium-example/build_chromium_tests.sh @@ -59,10 +59,10 @@ else fi echo "Generating ninja projects" -gn gen --args="use_remoteexec=true reclient_cfg_dir=\"../../buildtools/reclient_cfgs/linux\"" out/Default +gn gen --args="use_remoteexec=true use_siso=true" out/Default # Fetch cache and schedular IP address for passing to ninja NATIVELINK=$(kubectl get gtw nativelink-gateway -o=jsonpath='{.status.addresses[0].value}') echo "Starting autoninja build" -RBE_service=${NATIVELINK}:80 RBE_cas_service=${NATIVELINK}:80 RBE_instance='' RBE_reclient_timeout=60m RBE_exec_timeout=4m RBE_alsologtostderr=true RBE_service_no_security=true RBE_service_no_auth=true RBE_local_resource_fraction=0.00001 RBE_automatic_auth=false RBE_gcert_refresh_timeout=20 RBE_compression_threshold=-1 RBE_metrics_namespace='' RBE_platform='' RBE_experimental_credentials_helper='' RBE_experimental_credentials_helper_args='' RBE_log_http_calls=true RBE_use_rpc_credentials=false RBE_exec_strategy=remote_local_fallback autoninja -v -j 50 -C out/Default cc_unittests +SISO_REAPI_ADDRESS=${NATIVELINK}:80 SISO_REAPI_CAS_ADDRESS=${NATIVELINK}:80 SISO_REAPI_INSTANCE='' RBE_service_no_security=true autoninja -v -j 50 -C out/Default cc_unittests diff --git a/deployment-examples/docker-compose/Dockerfile b/deployment-examples/docker-compose/Dockerfile index 06d98d4c5..b41a7e949 100644 --- a/deployment-examples/docker-compose/Dockerfile +++ b/deployment-examples/docker-compose/Dockerfile @@ -1,3 +1,5 @@ +# syntax=docker/dockerfile:1 + # Copyright 2022-2025 The NativeLink Authors. All rights reserved. # # Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); @@ -14,8 +16,11 @@ # Current supported Ubuntu version, Noble Numbat aka 24.04 LTS # Locked down to a specific revision to avoid issues with package versions -ARG BAZELISK_URL=https://github.com/bazelbuild/bazelisk/releases/download/v1.25.0/bazelisk-linux-amd64 -ARG BAZELISK_SHA256=fd8fdff418a1758887520fa42da7e6ae39aefc788cf5e7f7bb8db6934d279fc4 +# Bazelisk (the Bazel launcher). Defaults are picked per build architecture +# (linux-amd64 vs linux-arm64) in the dependencies stage; override these to +# pin a specific binary. +ARG BAZELISK_URL +ARG BAZELISK_SHA256 # `--compilation_mode` to pass into bazel (eg: opt, dbg, fastbuild). ARG OPT_LEVEL=opt # Additional bazel flags. @@ -27,7 +32,19 @@ ARG ADDITIONAL_SETUP_WORKER_CMD= FROM ubuntu:noble-20250925@sha256:728785b59223d755e3e5c5af178fab1be7031f3522c5ccd7a0b32b80d8248123 AS dependencies ARG BAZELISK_URL ARG BAZELISK_SHA256 -RUN apt-get update \ +ARG TARGETARCH +COPY ./tools/bazel-retry.sh /usr/local/bin/bazel-retry +RUN ARCH_SUFFIX=amd64 \ + && if [ "$TARGETARCH" = "arm64" ]; then ARCH_SUFFIX=arm64; fi \ + && BAZELISK_URL="${BAZELISK_URL:-https://github.com/bazelbuild/bazelisk/releases/download/v1.25.0/bazelisk-linux-${ARCH_SUFFIX}}" \ + && if [ -z "$BAZELISK_SHA256" ]; then \ + if [ "$TARGETARCH" = "arm64" ]; then \ + BAZELISK_SHA256=4c8d966e40ac2c4efcc7f1a5a5cceef2c0a2f16b957e791fa7a867cce31e8fcb; \ + else \ + BAZELISK_SHA256=fd8fdff418a1758887520fa42da7e6ae39aefc788cf5e7f7bb8db6934d279fc4; \ + fi; \ + fi \ + && apt-get update \ && DEBIAN_FRONTEND=noninteractive \ apt-get install --no-install-recommends -y \ git=1:2.43.0-1ubuntu7.3 \ @@ -37,7 +54,8 @@ RUN apt-get update \ ca-certificates=20240203 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ - && python3 -c 'import hashlib, pathlib, stat, sys, urllib.request; data = urllib.request.urlopen(sys.argv[1], timeout=60).read(); digest = hashlib.sha256(data).hexdigest(); assert digest == sys.argv[2], f"sha256 mismatch: {digest}"; path = pathlib.Path("/usr/local/bin/bazel"); path.write_bytes(data); path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)' "$BAZELISK_URL" "$BAZELISK_SHA256" + && python3 -c 'import hashlib, pathlib, stat, sys, urllib.request; data = urllib.request.urlopen(sys.argv[1], timeout=60).read(); digest = hashlib.sha256(data).hexdigest(); assert digest == sys.argv[2], f"sha256 mismatch: {digest}"; path = pathlib.Path("/usr/local/bin/bazel"); path.write_bytes(data); path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)' "$BAZELISK_URL" "$BAZELISK_SHA256" \ + && chmod +x /usr/local/bin/bazel-retry # Build the binary. FROM dependencies AS builder @@ -46,7 +64,8 @@ COPY . . ARG OPT_LEVEL ARG ADDITIONAL_BAZEL_FLAGS # Add startup options to prevent Bazel server issues on ARM64 -RUN bazel \ +RUN --mount=type=secret,id=nativelink-bazelrc,target=/root/nativelink/user.bazelrc \ + bazel-retry \ --batch \ --output_base=/tmp/bazel_output \ build -c ${OPT_LEVEL} ${ADDITIONAL_BAZEL_FLAGS} nativelink && \ @@ -59,7 +78,7 @@ COPY --from=builder /root/nativelink-bin /usr/local/bin/nativelink ARG ADDITIONAL_SETUP_WORKER_CMD RUN apt-get update \ - && apt-get install -y --no-install-recommends curl=8.5.0-2ubuntu10.9 \ + && apt-get install -y --no-install-recommends curl=8.5.0-2ubuntu10.11 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && bash -ueo pipefail -c "${ADDITIONAL_SETUP_WORKER_CMD}" \ diff --git a/deployment-examples/docker-compose/README.md b/deployment-examples/docker-compose/README.md index 35918d91d..a48790c4e 100644 --- a/deployment-examples/docker-compose/README.md +++ b/deployment-examples/docker-compose/README.md @@ -4,7 +4,7 @@ This guide explains how to run NativeLink with multiple workers using Docker Com ## Prerequisites -- **Architecture**: This setup currently only works on **x86_64/amd64** architectures. ARM64/Apple Silicon isn't supported for the test client container. +- **Architecture**: This setup supports **x86_64/amd64** and **ARM64** architectures, except for Apple Silicon, which is not supported by the test client container - **Google Cloud CLI**: If using the test client container from `gcr.io/bazel-public/bazel`, you'll need: 1. [Google Cloud SDK](https://cloud.google.com/sdk/docs/install) installed 2. Authentication via `gcloud auth login` diff --git a/deployment-examples/docker-compose/local-storage-cas.json5 b/deployment-examples/docker-compose/local-storage-cas.json5 index 6d4acdeed..64e1c8d40 100644 --- a/deployment-examples/docker-compose/local-storage-cas.json5 +++ b/deployment-examples/docker-compose/local-storage-cas.json5 @@ -13,8 +13,8 @@ }, backend: { filesystem: { - content_path: "~/.cache/nativelink/content_path-cas", - temp_path: "~/.cache/nativelink/tmp_path-cas", + content_path: "/root/.cache/nativelink/content_path-cas", + temp_path: "/root/.cache/nativelink/tmp_path-cas", eviction_policy: { // 10gb. max_bytes: 10000000000, @@ -23,11 +23,25 @@ }, }, }, + { + // Holds blob-to-chunks layouts for the SplitBlob/SpliceBlob RPCs used + // by Bazel's --experimental_remote_cache_chunking. Must not verify + // digests and must not be the same store as the CAS. + name: "CHUNK_INDEX_STORE", + filesystem: { + content_path: "/root/.cache/nativelink/content_path-chunk-index", + temp_path: "/root/.cache/nativelink/tmp_path-chunk-index", + eviction_policy: { + // 100mb. + max_bytes: 100000000, + }, + }, + }, { name: "AC_MAIN_STORE", filesystem: { - content_path: "~/.cache/nativelink/content_path-ac", - temp_path: "~/.cache/nativelink/tmp_path-ac", + content_path: "/root/.cache/nativelink/content_path-ac", + temp_path: "/root/.cache/nativelink/tmp_path-ac", eviction_policy: { // 500mb. max_bytes: 500000000, @@ -40,12 +54,29 @@ listener: { http: { socket_address: "0.0.0.0:50051", + + // TODO(palfrey): These are only tested here so far + advanced_http: { + http2_keep_alive_interval: 60, + experimental_http2_keep_alive_timeout: 20, + experimental_http2_max_concurrent_streams: 2000, + experimental_http2_max_pending_accept_reset_streams: 2000, + experimental_http2_initial_connection_window_size: 16777216, + experimental_http2_initial_stream_window_size: 8388608, + }, }, }, services: { cas: [ { cas_store: "CAS_MAIN_STORE", + + // Optional: enables content-defined chunking + // (SplitBlob/SpliceBlob) for Bazel clients running with + // --experimental_remote_cache_chunking. + experimental_chunking: { + index_store: "CHUNK_INDEX_STORE", + }, }, ], ac: [ diff --git a/deployment-examples/docker-compose/scheduler-multi-worker.json5 b/deployment-examples/docker-compose/scheduler-multi-worker.json5 index 18a28333f..380f73b6f 100644 --- a/deployment-examples/docker-compose/scheduler-multi-worker.json5 +++ b/deployment-examples/docker-compose/scheduler-multi-worker.json5 @@ -3,7 +3,7 @@ { name: "GRPC_LOCAL_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ @@ -17,7 +17,7 @@ { name: "GRPC_LOCAL_AC_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ diff --git a/deployment-examples/docker-compose/scheduler.json5 b/deployment-examples/docker-compose/scheduler.json5 index 18a28333f..380f73b6f 100644 --- a/deployment-examples/docker-compose/scheduler.json5 +++ b/deployment-examples/docker-compose/scheduler.json5 @@ -3,7 +3,7 @@ { name: "GRPC_LOCAL_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ @@ -17,7 +17,7 @@ { name: "GRPC_LOCAL_AC_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ diff --git a/deployment-examples/docker-compose/worker-shared-cas.json5 b/deployment-examples/docker-compose/worker-shared-cas.json5 index 1198cde34..7c8aedc49 100644 --- a/deployment-examples/docker-compose/worker-shared-cas.json5 +++ b/deployment-examples/docker-compose/worker-shared-cas.json5 @@ -3,7 +3,7 @@ { name: "GRPC_LOCAL_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ @@ -17,7 +17,7 @@ { name: "GRPC_LOCAL_AC_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ diff --git a/deployment-examples/docker-compose/worker.json5 b/deployment-examples/docker-compose/worker.json5 index 7e55b0f17..ae2afb881 100644 --- a/deployment-examples/docker-compose/worker.json5 +++ b/deployment-examples/docker-compose/worker.json5 @@ -3,7 +3,7 @@ { name: "GRPC_LOCAL_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ @@ -17,7 +17,7 @@ { name: "GRPC_LOCAL_AC_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ diff --git a/flake.lock b/flake.lock index 19ee81e21..94045cb1a 100644 --- a/flake.lock +++ b/flake.lock @@ -115,11 +115,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1774106199, - "narHash": "sha256-US5Tda2sKmjrg2lNHQL3jRQ6p96cgfWh3J1QBliQ8Ws=", + "lastModified": 1783224372, + "narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6c9a78c09ff4d6c21d0319114873508a6ec01655", + "rev": "d407951447dcd00442e97087bf374aad70c04cea", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 6d13a546a..350c17130 100644 --- a/flake.nix +++ b/flake.nix @@ -205,6 +205,12 @@ docs = pkgs.callPackage ./tools/docs.nix {rust = pkgs.lre.stable-rust;}; + bazel = pkgs.writeShellScriptBin "bazel" '' + unset TMPDIR TMP + exec ${pkgs.bazelisk}/bin/bazelisk "$@" + ''; + bazel-retry = pkgs.writeScriptBin "bazel-retry" (builtins.readFile ./tools/bazel-retry.sh); + inherit (nix2container.packages.${system}.nix2container) pullImage; inherit (nix2container.packages.${system}.nix2container) buildImage; @@ -437,7 +443,7 @@ inherit nativelink mongodb wait4x bazelisk; }; rbe-toolchain-with-nativelink-test = pkgs.callPackage toolchain-examples/rbe-toolchain-test.nix { - inherit nativelink bazelisk; + inherit nativelink bazel-retry bazel; }; buck2-with-nativelink-test = pkgs.callPackage integration_tests/buck2/buck2-with-nativelink-test.nix { inherit nativelink buck2; @@ -469,7 +475,6 @@ hooks = import ./tools/pre-commit-hooks.nix { inherit pkgs; inherit (packages) generate-bazel-rc generate-stores-config; - renovate-patched = pkgs.callPackage ./tools/renovate.nix {}; nightly-rust = pkgs.rust-bin.nightly.${pkgs.lre.nightly-rust.meta.version}; }; }; @@ -511,12 +516,7 @@ "${gnused}/bin" ]; devShells.default = pkgs.mkShell { - packages = let - bazel = pkgs.writeShellScriptBin "bazel" '' - unset TMPDIR TMP - exec ${pkgs.bazelisk}/bin/bazelisk "$@" - ''; - in + packages = [ # Development tooling pkgs.git @@ -528,6 +528,7 @@ # Rust bazel + bazel-retry pkgs.lre.stable-rust pkgs.lre.lre-rs.lre-rs-configs-gen pkgs.rust-analyzer @@ -606,7 +607,7 @@ export CC=clang export PULUMI_K8S_AWAIT_ALL=true export PLAYWRIGHT_BROWSERS_PATH=${pkgs.playwright-driver.browsers} - export PLAYWRIGHT_NODEJS_PATH=${pkgs.nodePackages_latest.nodejs} + export PLAYWRIGHT_NODEJS_PATH=${pkgs.nodejs} '' # TODO(palfrey): Generalize this. + pkgs.lib.optionalString (system == "x86_64-linux") '' diff --git a/integration_tests/chunking_cache_test.sh b/integration_tests/chunking_cache_test.sh new file mode 100755 index 000000000..7833b4124 --- /dev/null +++ b/integration_tests/chunking_cache_test.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Copyright 2026 The NativeLink Authors. All rights reserved. +# +# Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# See LICENSE file for details +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Sanity check for REAPI content-defined chunking: uploads a large blob via +# SpliceBlob (Bazel --experimental_remote_cache_chunking), verifies the +# server registered a chunk layout, then re-fetches the blob from the remote +# cache via the chunked download path and checks it is byte-identical. + +if [[ $UNDER_TEST_RUNNER -ne 1 ]]; then + echo "This script should be run under run_integration_tests.sh" + exit 1 +fi + +# This test uploads a locally-built output to exercise the chunked write path +# (see CHUNKING_FLAGS below), which the repo-wide +# --remote_upload_local_results=false disables. To keep that anti-poisoning +# default intact for PR/developer lanes, this test runs only where local +# uploads are explicitly enabled: merges to main and the scheduled canary set +# NL_LOCAL_UPLOADS=1 (see main.yaml / nativelink-cloud-canary.yaml). +if [[ ${NL_LOCAL_UPLOADS:-0} != "1" ]]; then + echo "Skipping $(basename "$0"): requires local cache uploads (main/canary lanes only)." + exit 0 +fi +set -x + +# Bazel uploads cache entries in the background by default +# (--remote_cache_async, on since Bazel 8), so a build can return before the +# chunked upload and SpliceBlob complete. Force synchronous uploads so the +# chunk-index assertions below cannot race the upload. +# +# nativelink.bazelrc sets `build --remote_upload_local_results=false` +# repo-wide, and CI's setup-nativelink-cloud action writes the same into +# user.bazelrc for read-mode lanes. That suppresses the upload of this +# locally-built genrule output, so the server never registers a chunk layout +# and the index assertion below fails. Re-enable uploads for this test only +# (a command-line flag overrides the rc default); this is independent of the +# digest function -- chunking works under both sha256 and blake3. +CHUNKING_FLAGS=(--config self_test --experimental_remote_cache_chunking + --remote_cache_async=false --remote_upload_local_results=true) +EXPECTED_SHA=$(seq 1 1000000 | sha256sum | awk '{print $1}') +# The test runner's working directory is not the workspace root, so resolve +# the output location through bazel itself. +ARTIFACT="$(bazel --output_base="$BAZEL_CACHE_DIR" info "${CHUNKING_FLAGS[@]}" bazel-bin)/chunking_test_artifact.txt" + +# First build executes the action locally and uploads the ~6.9MB output as +# chunks (SpliceBlob). +bazel --output_base="$BAZEL_CACHE_DIR" build "${CHUNKING_FLAGS[@]}" //:chunking_test_artifact +FIRST_SHA=$(sha256sum "$ARTIFACT" | awk '{print $1}') +if [[ $FIRST_SHA != "$EXPECTED_SHA" ]]; then + echo "Expected locally built artifact to have sha $EXPECTED_SHA, got $FIRST_SHA." + exit 1 +fi + +# The server must have registered a chunk layout for the spliced blob. The +# index store is mounted from the host by docker-compose. +CHUNK_INDEX_DIR="${NATIVELINK_DIR:-$HOME/.cache/nativelink}/content_path-chunk-index" +if [[ -z $(find "$CHUNK_INDEX_DIR" -type f 2> /dev/null) ]]; then + echo "Expected a chunk layout in $CHUNK_INDEX_DIR after a chunked upload." + echo "SpliceBlob was likely not used; check that the server advertises" + echo "chunking support and that bazel supports the chunking flag." + echo "Diagnostics: contents of the mounted cache dir and root's default:" + sudo find "${NATIVELINK_DIR:-$HOME/.cache/nativelink}" -maxdepth 1 2> /dev/null || true + sudo find /root/.cache/nativelink -maxdepth 1 2> /dev/null || true + exit 1 +fi + +# Clean our local cache and re-fetch from the remote cache through the +# chunked download path. +bazel --output_base="$BAZEL_CACHE_DIR" clean +OUTPUT=$(bazel --output_base="$BAZEL_CACHE_DIR" build "${CHUNKING_FLAGS[@]}" //:chunking_test_artifact 2>&1) +if [[ ! $OUTPUT =~ 'remote cache hit' ]]; then + echo "Expected second bazel run to be a remote cache hit." + echo "STDOUT:" + echo "$OUTPUT" + exit 1 +fi +SECOND_SHA=$(sha256sum "$ARTIFACT" | awk '{print $1}') +if [[ $SECOND_SHA != "$EXPECTED_SHA" ]]; then + echo "Artifact fetched through the chunked download path is corrupt:" + echo "expected sha $EXPECTED_SHA, got $SECOND_SHA." + exit 1 +fi diff --git a/integration_tests/generate_redis_keys.py b/integration_tests/generate_redis_keys.py new file mode 100644 index 000000000..4b954f45c --- /dev/null +++ b/integration_tests/generate_redis_keys.py @@ -0,0 +1,6 @@ +from sys import stderr + + +for i in range(1000000): + print('set name'+str(i),'helloworld') + print(i, file=stderr) diff --git a/integration_tests/simple_cache_test.sh b/integration_tests/simple_cache_test.sh index 4e704464e..e4368f24c 100644 --- a/integration_tests/simple_cache_test.sh +++ b/integration_tests/simple_cache_test.sh @@ -19,10 +19,27 @@ if [[ $UNDER_TEST_RUNNER -ne 1 ]]; then echo "This script should be run under run_integration_tests.sh" exit 1 fi + +# This test uploads a locally-run test result to the cache and asserts the +# re-run is a cache hit, so it needs --remote_upload_local_results=true. +# nativelink.bazelrc sets that false repo-wide to stop PR/developer lanes from +# writing to the *shared* cache (cache-poisoning guard). Uploads here target +# only the ephemeral, per-run docker-compose cache, so they are safe -- but to +# keep the anti-poisoning default intact this test runs only where local +# uploads are explicitly enabled: merges to main and the scheduled canary set +# NL_LOCAL_UPLOADS=1 (see main.yaml / nativelink-cloud-canary.yaml). +if [[ ${NL_LOCAL_UPLOADS:-0} != "1" ]]; then + echo "Skipping $(basename "$0"): requires local cache uploads (main/canary lanes only)." + exit 0 +fi set -x +# A command-line flag overrides the repo-wide --remote_upload_local_results +# =false so this test can populate the cache it then asserts on. +TEST_FLAGS=(--config self_test --remote_upload_local_results=true) + # First run our test under bazel. It should not be cached. -OUTPUT=$(bazel --output_base="$BAZEL_CACHE_DIR" test --config self_test //:dummy_test) +OUTPUT=$(bazel --output_base="$BAZEL_CACHE_DIR" test "${TEST_FLAGS[@]}" //:dummy_test) if [[ $OUTPUT =~ .*'(cached)'.* ]]; then echo "Expected first bazel run to not have test cached." echo "STDOUT:" @@ -34,7 +51,7 @@ fi bazel --output_base="$BAZEL_CACHE_DIR" clean # Now run it under bazel again. This time the remote cache should have it. -OUTPUT=$(bazel --output_base="$BAZEL_CACHE_DIR" test --config self_test //:dummy_test) +OUTPUT=$(bazel --output_base="$BAZEL_CACHE_DIR" test "${TEST_FLAGS[@]}" //:dummy_test) if [[ ! $OUTPUT =~ .*'(cached)'.* ]]; then echo "Expected second bazel run to have test cached." echo "STDOUT:" diff --git a/kubernetes/components/worker/worker.json5 b/kubernetes/components/worker/worker.json5 index d68c57d55..01f729bb3 100644 --- a/kubernetes/components/worker/worker.json5 +++ b/kubernetes/components/worker/worker.json5 @@ -3,7 +3,7 @@ { name: "GRPC_LOCAL_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ @@ -17,7 +17,7 @@ { name: "GRPC_LOCAL_AC_STORE", - // Note: This file is used to test GRPC store. + // Note: This file is used to test gRPC store. grpc: { instance_name: "", endpoints: [ diff --git a/kubernetes/nativelink/nativelink-config.json5 b/kubernetes/nativelink/nativelink-config.json5 index 630d1505f..22200d092 100644 --- a/kubernetes/nativelink/nativelink-config.json5 +++ b/kubernetes/nativelink/nativelink-config.json5 @@ -94,7 +94,7 @@ { name: "MAIN_SCHEDULER", - // TODO(palfrey): use the right scheduler because reclient doesn't use the cached results? + // TODO(palfrey): use the right scheduler because siso doesn't use the cached results? // TODO(palfrey): max_bytes_per_stream simple: { supported_platform_properties: { diff --git a/local-remote-execution/MODULE.bazel b/local-remote-execution/MODULE.bazel index 8c95cf2ec..67b31b9c5 100644 --- a/local-remote-execution/MODULE.bazel +++ b/local-remote-execution/MODULE.bazel @@ -10,11 +10,12 @@ module( bazel_dep(name = "platforms", version = "1.1.0") # Use the starlark implementation of C++ rules instead of the builtin ones. -bazel_dep(name = "rules_cc", version = "0.2.18") +bazel_dep(name = "rules_cc", version = "0.2.20") # Use the starlark implementation of Java rules instead of the builtin ones. bazel_dep(name = "rules_java", version = "8.11.0") -bazel_dep(name = "rules_rs", version = "0.0.76") +bazel_dep(name = "rules_rs", version = "0.0.102") +bazel_dep(name = "llvm", version = "0.8.15") bazel_dep(name = "rules_rust", version = "0.68.1") bazel_dep(name = "bazel_skylib", version = "1.9.0") # rules_rust is pinned to the hermeticbuild fork in the parent MODULE.bazel via diff --git a/local-remote-execution/MODULE.bazel.lock b/local-remote-execution/MODULE.bazel.lock index a20eb23b9..d1b33fced 100644 --- a/local-remote-execution/MODULE.bazel.lock +++ b/local-remote-execution/MODULE.bazel.lock @@ -1,5 +1,5 @@ { - "lockFileVersion": 26, + "lockFileVersion": 28, "registryFileHashes": { "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", @@ -21,8 +21,6 @@ "https://bcr.bazel.build/modules/apple_support/1.24.1/MODULE.bazel": "f46e8ddad60aef170ee92b2f3d00ef66c147ceafea68b6877cb45bd91737f5f8", "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4", "https://bcr.bazel.build/modules/apple_support/1.24.2/source.json": "2c22c9827093250406c5568da6c54e6fdf0ef06238def3d99c71b12feb057a8d", - "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183", - "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/source.json": "605086bbc197743a0d360f7ddc550a1d4dfa0441bc807236e17170f636153348", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", "https://bcr.bazel.build/modules/bazel_features/1.10.0/MODULE.bazel": "f75e8807570484a99be90abcd52b5e1f390362c258bcb73106f4544957a48101", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", @@ -43,9 +41,10 @@ "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", "https://bcr.bazel.build/modules/bazel_features/1.42.0/MODULE.bazel": "e8ca15cb2639c5f12183db6dcb678735555d0cdd739b32a0418b6532b5e565f8", "https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080", - "https://bcr.bazel.build/modules/bazel_features/1.43.0/MODULE.bazel": "defa2226f06ba20550d6548c3a2ea2a7929634437a52973869c20c225450eb91", "https://bcr.bazel.build/modules/bazel_features/1.45.0/MODULE.bazel": "7daec6d87ab0703417486d4cb948af0b06f55d4d7c08cbb5978c80e79b538edf", - "https://bcr.bazel.build/modules/bazel_features/1.45.0/source.json": "635e4536e09ff125b8972e0fa239c135fde5f18701f7d5115680560651dfb41d", + "https://bcr.bazel.build/modules/bazel_features/1.47.0/MODULE.bazel": "e34df3cb35b1684cfa69923a61ae3803595babd3942cd306a488d51400886b30", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/MODULE.bazel": "2083ef9c7a469f520890483ccf8e0189d6e71e2117e7752e15e6554433d5ae3e", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/source.json": "e0ee3debde2789ff56e4452e612d126925ba9ab64d4bde79c67f099d2902df9b", "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d", @@ -69,6 +68,8 @@ "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0", "https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f", "https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd", + "https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/MODULE.bazel": "29ecf4babfd3c762be00d7573c288c083672ab60e79c833ff7f49ee662e54471", + "https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/source.json": "8be4a3ef2599693f759e5c0990a4cc5a246ac08db4c900a38f852ba25b5c39be", "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/MODULE.bazel": "f1b7bb2dd53e8f2ef984b39485ec8a44e9076dda5c4b8efd2fb4c6a6e856a31d", "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/source.json": "ebe931bfe362e4b41e59ee00a528db6074157ff2ced92eb9e970acab2e1089c9", "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", @@ -78,12 +79,15 @@ "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.8/MODULE.bazel": "3be7b0faca6f1e69e89197999e0b01ce058c42f3e764ef028466f7e0ff77c761", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.8/source.json": "8403718636114198fca6ea04b437fa001ac7167b4d485102defb0a6f7d11bc08", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", - "https://bcr.bazel.build/modules/llvm/0.7.7/MODULE.bazel": "0eeaf1814feca77abc7af3523e2b9d3735f92e2583043f8d6a2cc0fb5f479a28", - "https://bcr.bazel.build/modules/llvm/0.7.7/source.json": "7c8910307329462a21b7bdcc52710360da3de8284738dca52241bb15302a00dc", + "https://bcr.bazel.build/modules/llvm/0.8.15/MODULE.bazel": "2a6f808abd87d6037a435d98816b46ccb4773caa4b1923dea5c02d0a21c9dc19", + "https://bcr.bazel.build/modules/llvm/0.8.15/source.json": "994db3a9052966be153f329219ee9ef163ecbc1e505bbd78079af14c1e24f767", + "https://bcr.bazel.build/modules/llvm/0.8.9/MODULE.bazel": "9e35ff5bcac996f9edc1b44b8f8baa58c7855e742c5608b07d925dcdbe642100", "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", "https://bcr.bazel.build/modules/package_metadata/0.0.7/MODULE.bazel": "7adb03933fc8401f495800cf4eafcff0edc6da0ff55c7db223ef69d19f689486", @@ -136,8 +140,9 @@ "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37", "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84", - "https://bcr.bazel.build/modules/rules_cc/0.2.18/MODULE.bazel": "4460ec36adc8f722a6a2a4ac9374cb91f2acebadaa93fc37966129afb3dece87", - "https://bcr.bazel.build/modules/rules_cc/0.2.18/source.json": "abad668ff2fd63ada1ac49bf386d37e27048b89a3465a6fd968bb832b00a09d3", + "https://bcr.bazel.build/modules/rules_cc/0.2.19/MODULE.bazel": "d5e0f05b63273281a16654eb6b1a8742a75ec153ac8b4f0419949d6e401e46f0", + "https://bcr.bazel.build/modules/rules_cc/0.2.20/MODULE.bazel": "f5c07bce5ddcb99be21a0812ff5aadb439e688b7449c6542152363b2fd859c1a", + "https://bcr.bazel.build/modules/rules_cc/0.2.20/source.json": "1155433dc6b8161bc339ce94095b337ed95feb1f048b014e10b62339d4b4239c", "https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc", "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", @@ -190,8 +195,8 @@ "https://bcr.bazel.build/modules/rules_python/1.6.3/MODULE.bazel": "a7b80c42cb3de5ee2a5fa1abc119684593704fcd2fec83165ebe615dec76574f", "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", "https://bcr.bazel.build/modules/rules_python/1.7.0/source.json": "028a084b65dcf8f4dc4f82f8778dbe65df133f234b316828a82e060d81bdce32", - "https://bcr.bazel.build/modules/rules_rs/0.0.76/MODULE.bazel": "461dcf664f368fdc921f67ea20ec1bc78c73f65a0a20b6e2a6d4b1c77fbde8c1", - "https://bcr.bazel.build/modules/rules_rs/0.0.76/source.json": "167eb1122e0f74848fc995b581061155dda1dfd600a38c253a85ef46d0523221", + "https://bcr.bazel.build/modules/rules_rs/0.0.102/MODULE.bazel": "6c64a272531e59dc2a55726117a4ca3161c6301fd69af3bd1038465730e86632", + "https://bcr.bazel.build/modules/rules_rs/0.0.102/source.json": "e0bb950a7126037e2bf5b341e88012fd393d68715489dccce54780f50e6df9ca", "https://bcr.bazel.build/modules/rules_rust/0.68.1/MODULE.bazel": "8d3332ef4079673385eb81f8bd68b012decc04ac00c9d5a01a40eff90301732c", "https://bcr.bazel.build/modules/rules_rust/0.68.1/source.json": "3378e746f81b62457fdfd37391244fa8ff075ba85c05931ee4f3a20ac1efe963", "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", @@ -210,17 +215,889 @@ "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f", - "https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445", - "https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/MODULE.bazel": "e8f9ff79199e8d9eaad7f1b0a77ad74b30bb82d794b87d8ca942bead5de83ae9", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/source.json": "20143442376c03426f6135292ba02d825cb75308aa47e6bf42dd4cc5a435c2ff", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/MODULE.bazel": "b573395fe63aef4299ba095173e2f62ccfee5ad9bbf7acaa95dba73af9fc2b38", "https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/source.json": "3f3fbaeafecaf629877ad152a2c9def21f8d330d91aa94c5dc75bbb98c10b8b8", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.8/MODULE.bazel": "e48a69bd54053c2ec5fffc2a29fb70122afd3e83ab6c07068f63bc6553fa57cc", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.8/source.json": "bd7e928ccd63505b44f4784f7bbf12cc11f9ff23bf3ca12ff2c91cd74846099e", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" }, "selectedYankedVersions": {}, - "moduleExtensions": {}, - "facts": {} + "moduleExtensions": { + "//rust:extension.bzl%lre_rs": { + "general": { + "bzlTransitiveDigest": "uG+JZDxQyPELNihTm54EkV+15PXyp8wI4w/Peu5bXa4=", + "usagesDigest": "f99DFrGxUJaJEgSBcbdR/QB7bPV/EOQbpEvO2ywcOb8=", + "recordedInputs": [ + "REPO_MAPPING:,bazel_tools bazel_tools" + ], + "generatedRepoSpecs": { + "lre-rs-stable-aarch64-darwin": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:aarch64-darwin.BUILD.bazel", + "path": "/nix/store/2mchcvza9v1j5mx67r4770plmrkm0f68-rust-default-1.93.1" + } + }, + "lre-rs-nightly-aarch64-darwin": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:aarch64-darwin.BUILD.bazel", + "path": "/nix/store/1dysg6qbzyb7vanwsc5y756zmb0227z9-rust-default-1.96.0-nightly-2026-03-24" + } + }, + "lre-rs-stable-aarch64-linux": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:aarch64-linux.BUILD.bazel", + "path": "/nix/store/vx2ziqrqc0qj0pjng71cpcyainq52xqd-rust-default-1.93.1" + } + }, + "lre-rs-nightly-aarch64-linux": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:aarch64-linux.BUILD.bazel", + "path": "/nix/store/zl02i3a6zzw5mxd665y2n7mp97ajdwkx-rust-default-1.96.0-nightly-2026-03-24" + } + }, + "lre-rs-stable-x86_64-darwin": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:x86_64-darwin.BUILD.bazel", + "path": "/nix/store/qjpia0l98w7wpf9b3nzfb24y8rxh52cg-rust-default-1.93.1" + } + }, + "lre-rs-nightly-x86_64-darwin": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:x86_64-darwin.BUILD.bazel", + "path": "/nix/store/wdyvk55ys5m7shpp6jw9d8116m3dlmjd-rust-default-1.96.0-nightly-2026-03-24" + } + }, + "lre-rs-stable-x86_64-linux": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:x86_64-linux.BUILD.bazel", + "path": "/nix/store/cgzz6kbvvhxh4k71rlj9wj14mdbn02n9-rust-default-1.93.1" + } + }, + "lre-rs-nightly-x86_64-linux": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:local.bzl%new_local_repository", + "attributes": { + "build_file": "@@//rust:x86_64-linux.BUILD.bazel", + "path": "/nix/store/5pysp36qjzbwdjx9zlj9sjc43zhbiwyn-rust-default-1.96.0-nightly-2026-03-24" + } + } + } + } + }, + "@@protobuf+//python/dist:system_python.bzl%system_python_extension": { + "general": { + "bzlTransitiveDigest": "pmsA+awieucfllLc2n7k8xEoPp0i5LF9Hw6mGX0cqSQ=", + "usagesDigest": "A+RWmbKdBBwZcBbNGNvfPbqG2vYZRjVrFp6x1iRUrAk=", + "recordedInputs": [], + "generatedRepoSpecs": { + "system_python": { + "repoRuleId": "@@protobuf+//python/dist:system_python.bzl%system_python", + "attributes": { + "minimum_python_version": "3.9" + } + } + } + } + }, + "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { + "general": { + "bzlTransitiveDigest": "NRXra7941UfmNUyIxnLt82V5hULluVGL2nBsijTl4j4=", + "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=", + "recordedInputs": [ + "REPO_MAPPING:pybind11_bazel+,bazel_tools bazel_tools", + "FILE:@@pybind11_bazel+//MODULE.bazel e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" + ], + "generatedRepoSpecs": { + "pybind11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel", + "strip_prefix": "pybind11-2.12.0", + "urls": [ + "https://github.com/pybind/pybind11/archive/v2.12.0.zip" + ] + } + } + } + } + }, + "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "+Kp6j204mBZ3mxlIDDR0gBoP45BZ4jYRhRAcB8sU0qc=", + "usagesDigest": "QI2z8ZUR+mqtbwsf2fLqYdJAkPOHdOV+tF2yVAUgRzw=", + "recordedInputs": [ + "REPO_MAPPING:rules_kotlin+,bazel_tools bazel_tools" + ], + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + } + } + }, + "@@rules_python+//python/extensions:config.bzl%config": { + "general": { + "bzlTransitiveDigest": "dzD8Q2YmrP3fz8saWLHPmlwPLO91ImtTmP/c9JKTStM=", + "usagesDigest": "ZVSXMAGpD+xzVNPuvF1IoLBkty7TROO0+akMapt1pAg=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,pypi__build rules_python++config+pypi__build", + "REPO_MAPPING:rules_python+,pypi__click rules_python++config+pypi__click", + "REPO_MAPPING:rules_python+,pypi__colorama rules_python++config+pypi__colorama", + "REPO_MAPPING:rules_python+,pypi__importlib_metadata rules_python++config+pypi__importlib_metadata", + "REPO_MAPPING:rules_python+,pypi__installer rules_python++config+pypi__installer", + "REPO_MAPPING:rules_python+,pypi__more_itertools rules_python++config+pypi__more_itertools", + "REPO_MAPPING:rules_python+,pypi__packaging rules_python++config+pypi__packaging", + "REPO_MAPPING:rules_python+,pypi__pep517 rules_python++config+pypi__pep517", + "REPO_MAPPING:rules_python+,pypi__pip rules_python++config+pypi__pip", + "REPO_MAPPING:rules_python+,pypi__pip_tools rules_python++config+pypi__pip_tools", + "REPO_MAPPING:rules_python+,pypi__pyproject_hooks rules_python++config+pypi__pyproject_hooks", + "REPO_MAPPING:rules_python+,pypi__setuptools rules_python++config+pypi__setuptools", + "REPO_MAPPING:rules_python+,pypi__tomli rules_python++config+pypi__tomli", + "REPO_MAPPING:rules_python+,pypi__wheel rules_python++config+pypi__wheel", + "REPO_MAPPING:rules_python+,pypi__zipp rules_python++config+pypi__zipp" + ], + "generatedRepoSpecs": { + "rules_python_internal": { + "repoRuleId": "@@rules_python+//python/private:internal_config_repo.bzl%internal_config_repo", + "attributes": { + "transition_setting_generators": {}, + "transition_settings": [] + } + }, + "pypi__build": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl", + "sha256": "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__click": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", + "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__colorama": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__importlib_metadata": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl", + "sha256": "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__installer": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl", + "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__more_itertools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl", + "sha256": "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__packaging": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", + "sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pep517": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl", + "sha256": "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl", + "sha256": "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip_tools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl", + "sha256": "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pyproject_hooks": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl", + "sha256": "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__setuptools": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/90/99/158ad0609729111163fc1f674a5a42f2605371a4cf036d0441070e2f7455/setuptools-78.1.1-py3-none-any.whl", + "sha256": "c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__tomli": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", + "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__wheel": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl", + "sha256": "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__zipp": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl", + "sha256": "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + } + } + } + }, + "@@rules_python+//python/uv:uv.bzl%uv": { + "general": { + "bzlTransitiveDigest": "ijW9KS7qsIY+yBVvJ+Nr1mzwQox09j13DnE3iIwaeTM=", + "usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,platforms platforms" + ], + "generatedRepoSpecs": { + "uv": { + "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo", + "attributes": { + "toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'", + "toolchain_names": [ + "none" + ], + "toolchain_implementations": { + "none": "'@@rules_python+//python:none'" + }, + "toolchain_compatible_with": { + "none": [ + "@platforms//:incompatible" + ] + }, + "toolchain_target_settings": {} + } + } + } + } + }, + "@@rules_rust+//crate_universe/private:internal_extensions.bzl%cu_nr": { + "general": { + "bzlTransitiveDigest": "J12jOIvWO2oITqmasxt2OT1huw9gqbPC3WfVCJnshhk=", + "usagesDigest": "v4We18mWSPeKV4GPp9Gne78W+jZOgP2pC1i4UN9br1g=", + "recordedInputs": [ + "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", + "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", + "REPO_MAPPING:rules_cc+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_cc+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_cc+,cc_compatibility_proxy rules_cc++compatibility_proxy+cc_compatibility_proxy", + "REPO_MAPPING:rules_cc+,platforms platforms", + "REPO_MAPPING:rules_cc+,rules_cc rules_cc+", + "REPO_MAPPING:rules_cc++compatibility_proxy+cc_compatibility_proxy,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,bazel_features bazel_features+", + "REPO_MAPPING:rules_rust+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_rust+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_rust+,cui rules_rust++cu+cui", + "REPO_MAPPING:rules_rust+,rrc rules_rust++i2+rrc", + "REPO_MAPPING:rules_rust+,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,rules_rust rules_rust+" + ], + "generatedRepoSpecs": { + "cargo_bazel_bootstrap": { + "repoRuleId": "@@rules_rust+//cargo/private:cargo_bootstrap.bzl%cargo_bootstrap_repository", + "attributes": { + "srcs": [ + "@@rules_rust+//crate_universe:src/api.rs", + "@@rules_rust+//crate_universe:src/api/lockfile.rs", + "@@rules_rust+//crate_universe:src/cli.rs", + "@@rules_rust+//crate_universe:src/cli/generate.rs", + "@@rules_rust+//crate_universe:src/cli/query.rs", + "@@rules_rust+//crate_universe:src/cli/render.rs", + "@@rules_rust+//crate_universe:src/cli/splice.rs", + "@@rules_rust+//crate_universe:src/cli/vendor.rs", + "@@rules_rust+//crate_universe:src/config.rs", + "@@rules_rust+//crate_universe:src/context.rs", + "@@rules_rust+//crate_universe:src/context/crate_context.rs", + "@@rules_rust+//crate_universe:src/context/platforms.rs", + "@@rules_rust+//crate_universe:src/lib.rs", + "@@rules_rust+//crate_universe:src/lockfile.rs", + "@@rules_rust+//crate_universe:src/main.rs", + "@@rules_rust+//crate_universe:src/metadata.rs", + "@@rules_rust+//crate_universe:src/metadata/cargo_bin.rs", + "@@rules_rust+//crate_universe:src/metadata/cargo_tree_resolver.rs", + "@@rules_rust+//crate_universe:src/metadata/cargo_tree_rustc_wrapper.bat", + "@@rules_rust+//crate_universe:src/metadata/cargo_tree_rustc_wrapper.sh", + "@@rules_rust+//crate_universe:src/metadata/dependency.rs", + "@@rules_rust+//crate_universe:src/metadata/metadata_annotation.rs", + "@@rules_rust+//crate_universe:src/rendering.rs", + "@@rules_rust+//crate_universe:src/rendering/template_engine.rs", + "@@rules_rust+//crate_universe:src/rendering/templates/module_bzl.j2", + "@@rules_rust+//crate_universe:src/rendering/templates/partials/header.j2", + "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/aliases_map.j2", + "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/deps_map.j2", + "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/repo_git.j2", + "@@rules_rust+//crate_universe:src/rendering/templates/partials/module/repo_http.j2", + "@@rules_rust+//crate_universe:src/rendering/templates/vendor_module.j2", + "@@rules_rust+//crate_universe:src/rendering/verbatim/alias_rules.bzl", + "@@rules_rust+//crate_universe:src/select.rs", + "@@rules_rust+//crate_universe:src/splicing.rs", + "@@rules_rust+//crate_universe:src/splicing/cargo_config.rs", + "@@rules_rust+//crate_universe:src/splicing/crate_index_lookup.rs", + "@@rules_rust+//crate_universe:src/splicing/splicer.rs", + "@@rules_rust+//crate_universe:src/test.rs", + "@@rules_rust+//crate_universe:src/utils.rs", + "@@rules_rust+//crate_universe:src/utils/starlark.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/glob.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/label.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/select.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/select_dict.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/select_list.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/select_scalar.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/select_set.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/serialize.rs", + "@@rules_rust+//crate_universe:src/utils/starlark/target_compatible_with.rs", + "@@rules_rust+//crate_universe:src/utils/symlink.rs", + "@@rules_rust+//crate_universe:src/utils/target_triple.rs" + ], + "binary": "cargo-bazel", + "cargo_lockfile": "@@rules_rust+//crate_universe:Cargo.lock", + "cargo_toml": "@@rules_rust+//crate_universe:Cargo.toml", + "version": "1.86.0", + "timeout": 900, + "rust_toolchain_cargo_template": "@rust_host_tools//:bin/{tool}", + "rust_toolchain_rustc_template": "@rust_host_tools//:bin/{tool}", + "compressed_windows_toolchain_names": false + } + } + }, + "moduleExtensionMetadata": { + "explicitRootModuleDirectDeps": [ + "cargo_bazel_bootstrap" + ], + "explicitRootModuleDirectDevDeps": [], + "useAllRepos": "NO", + "reproducible": false + } + } + } + }, + "facts": { + "@@rules_rs+//rs:extensions.bzl%crate": { + "adler2_2.0.1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[\"std\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[]}}", + "ahash_0.8.12": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"const-random\",\"optional\":true,\"req\":\"^0.1.17\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.2\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"hashbrown\",\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.2\"},{\"kind\":\"dev\",\"name\":\"no-panic\",\"req\":\"^0.1.10\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"once_cell\",\"req\":\"^1.18.0\",\"target\":\"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"pcg-mwc\",\"req\":\"^0.2.1\"},{\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"seahash\",\"req\":\"^4.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.59\"},{\"kind\":\"dev\",\"name\":\"smallvec\",\"req\":\"^1.13.1\"},{\"kind\":\"build\",\"name\":\"version_check\",\"req\":\"^0.9.4\"},{\"default_features\":false,\"features\":[\"simd\"],\"name\":\"zerocopy\",\"req\":\"^0.8.24\"}],\"features\":{\"atomic-polyfill\":[\"dep:portable-atomic\",\"once_cell/critical-section\"],\"compile-time-rng\":[\"const-random\"],\"default\":[\"std\",\"runtime-rng\"],\"nightly-arm-aes\":[],\"no-rng\":[],\"runtime-rng\":[\"getrandom\"],\"std\":[]}}", + "aho-corasick_1.1.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.3\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"default_features\":false,\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.4.0\"}],\"features\":{\"default\":[\"std\",\"perf-literal\"],\"logging\":[\"dep:log\"],\"perf-literal\":[\"dep:memchr\"],\"std\":[\"memchr?/std\"]}}", + "alloc-no-stdlib_2.0.4": "{\"dependencies\":[],\"features\":{\"unsafe\":[]}}", + "alloc-stdlib_0.2.2": "{\"dependencies\":[{\"name\":\"alloc-no-stdlib\",\"req\":\"^2.0.4\"}],\"features\":{\"unsafe\":[]}}", + "android_system_properties_0.1.5": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.126\"}],\"features\":{}}", + "anstream_1.0.0": "{\"dependencies\":[{\"name\":\"anstyle\",\"req\":\"^1.0.0\"},{\"name\":\"anstyle-parse\",\"req\":\"^1.0.0\"},{\"name\":\"anstyle-query\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"anstyle-wincon\",\"optional\":true,\"req\":\"^3.0.5\",\"target\":\"cfg(windows)\"},{\"name\":\"colorchoice\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"divan\",\"req\":\"^0.1.16\"},{\"name\":\"is_terminal_polyfill\",\"req\":\"^1.48\"},{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"owo-colors\",\"req\":\"^4.0.0\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.7.0\"},{\"kind\":\"dev\",\"name\":\"strip-ansi-escapes\",\"req\":\"^0.2.1\"},{\"name\":\"utf8parse\",\"req\":\"^0.2.2\"}],\"features\":{\"auto\":[\"dep:anstyle-query\"],\"default\":[\"auto\",\"wincon\"],\"test\":[],\"wincon\":[\"dep:anstyle-wincon\"]}}", + "anstyle-parse_1.0.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arrayvec\",\"optional\":true,\"req\":\"^0.7.6\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"codegenrs\",\"req\":\"^3.0.0\"},{\"kind\":\"dev\",\"name\":\"divan\",\"req\":\"^0.1.16\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.7.0\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.23\"},{\"name\":\"utf8parse\",\"optional\":true,\"req\":\"^0.2.2\"},{\"kind\":\"dev\",\"name\":\"vte_generate_state_changes\",\"req\":\"^0.1.2\"}],\"features\":{\"core\":[\"dep:arrayvec\"],\"default\":[\"utf8\"],\"utf8\":[\"dep:utf8parse\"]}}", + "anstyle-query_1.1.5": "{\"dependencies\":[{\"features\":[\"Win32_System_Console\",\"Win32_Foundation\"],\"name\":\"windows-sys\",\"req\":\">=0.60.2, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "anstyle-wincon_3.0.11": "{\"dependencies\":[{\"name\":\"anstyle\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.1\"},{\"name\":\"once_cell_polyfill\",\"req\":\"^1.56.1\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_System_Console\",\"Win32_Foundation\"],\"name\":\"windows-sys\",\"req\":\">=0.60.2, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "anstyle_1.0.14": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"lexopt\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^0.6.23\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "anyhow_1.0.102": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.6\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"backtrace\":[],\"default\":[\"std\"],\"std\":[]}}", + "ascii_1.1.0": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"name\":\"serde_test\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", + "async-trait_0.1.89": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.30\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"full\",\"parsing\",\"printing\",\"proc-macro\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.46\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.40\"},{\"kind\":\"dev\",\"name\":\"tracing-attributes\",\"req\":\"^0.1.27\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.81\"}],\"features\":{}}", + "atomic-waker_1.1.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"cargo_bench_support\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.7.0\"}],\"features\":{}}", + "autocfg_1.5.0": "{\"dependencies\":[],\"features\":{}}", + "axum-core_0.5.6": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1.2\"},{\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.0.0\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.25.0\"},{\"features\":[\"limit\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"limit\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.37\"}],\"features\":{\"__private_docs\":[\"dep:tower-http\"],\"tracing\":[\"dep:tracing\"]}}", + "axum_0.8.8": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"axum-core\",\"req\":\"^0.5.5\"},{\"name\":\"axum-macros\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"form_urlencoded\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.1.0\"},{\"features\":[\"client\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\"},{\"features\":[\"tokio\",\"server\",\"service\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.3\"},{\"name\":\"itoa\",\"req\":\"^1.0.5\"},{\"name\":\"matchit\",\"req\":\"=0.8.4\"},{\"name\":\"memchr\",\"req\":\"^2.4.1\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"multer\",\"optional\":true,\"req\":\"^3.0.0\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.211\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.221\"},{\"name\":\"serde_core\",\"req\":\"^1.0.221\"},{\"features\":[\"raw_value\"],\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"raw_value\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"serde_path_to_error\",\"optional\":true,\"req\":\"^0.1.8\"},{\"name\":\"serde_urlencoded\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"serde-human-readable\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\"},{\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^1.44\"},{\"features\":[\"macros\",\"rt\",\"rt-multi-thread\",\"net\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"package\":\"tokio\",\"req\":\"^1.44.2\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"name\":\"tokio-tungstenite\",\"optional\":true,\"req\":\"^0.28.0\"},{\"kind\":\"dev\",\"name\":\"tokio-tungstenite\",\"req\":\"^0.28.0\"},{\"default_features\":false,\"features\":[\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"util\",\"timeout\",\"limit\",\"load-shed\",\"steer\",\"filter\"],\"kind\":\"dev\",\"name\":\"tower\",\"package\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.2\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"features\":[\"serde\",\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"__private\":[\"tokio\",\"http1\",\"dep:reqwest\"],\"__private_docs\":[\"axum-core/__private_docs\",\"tower/full\",\"dep:serde\",\"dep:tower-http\"],\"default\":[\"form\",\"http1\",\"json\",\"matched-path\",\"original-uri\",\"query\",\"tokio\",\"tower-log\",\"tracing\"],\"form\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"http1\":[\"dep:hyper\",\"hyper?/http1\",\"hyper-util?/http1\"],\"http2\":[\"dep:hyper\",\"hyper?/http2\",\"hyper-util?/http2\"],\"json\":[\"dep:serde_json\",\"dep:serde_path_to_error\"],\"macros\":[\"dep:axum-macros\"],\"matched-path\":[],\"multipart\":[\"dep:multer\"],\"original-uri\":[],\"query\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"tokio\":[\"dep:hyper-util\",\"dep:tokio\",\"tokio/net\",\"tokio/rt\",\"tower/make\",\"tokio/macros\"],\"tower-log\":[\"tower/log\"],\"tracing\":[\"dep:tracing\",\"axum-core/tracing\"],\"ws\":[\"dep:hyper\",\"tokio\",\"dep:tokio-tungstenite\",\"dep:sha1\",\"dep:base64\"]}}", + "base64_0.13.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"=0.3.2\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.6.1\"},{\"kind\":\"dev\",\"name\":\"structopt\",\"req\":\"^0.3\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[]}}", + "base64_0.22.1": "{\"dependencies\":[{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^3.2.25\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.13.0\"},{\"kind\":\"dev\",\"name\":\"rstest_reuse\",\"req\":\"^0.6.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"strum\",\"req\":\"^0.25\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", + "bitflags_2.11.0": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"arbitrary\",\"req\":\"^1.0\"},{\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.12.2\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.228\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde_lib\",\"package\":\"serde\",\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.19\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.18\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"zerocopy\",\"req\":\"^0.8\"}],\"features\":{\"example_generated\":[],\"serde\":[\"serde_core\"],\"std\":[]}}", + "bitflags_2.11.1": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"arbitrary\",\"req\":\"^1.0\"},{\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"bytemuck\",\"req\":\"^1.12.2\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.228\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde_lib\",\"package\":\"serde\",\"req\":\"^1.0.103\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.19\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.18\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"zerocopy\",\"req\":\"^0.8\"}],\"features\":{\"example_generated\":[],\"serde\":[\"serde_core\"],\"std\":[]}}", + "brotli-decompressor_4.0.3": "{\"dependencies\":[{\"name\":\"alloc-no-stdlib\",\"req\":\"~2.0\"},{\"name\":\"alloc-stdlib\",\"optional\":true,\"req\":\"~0.2\"}],\"features\":{\"benchmark\":[],\"default\":[\"std\"],\"disable-timer\":[],\"ffi-api\":[],\"pass-through-ffi-panics\":[],\"seccomp\":[],\"std\":[\"alloc-stdlib\"],\"unsafe\":[\"alloc-no-stdlib/unsafe\",\"alloc-stdlib/unsafe\"]}}", + "buf_redux_0.8.4": "{\"dependencies\":[{\"name\":\"memchr\",\"req\":\"^2.0\"},{\"name\":\"safemem\",\"req\":\"^0.3\"},{\"name\":\"slice-deque\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(any(unix, windows))\"}],\"features\":{\"default\":[\"slice-deque\"],\"nightly\":[\"slice-deque/unstable\"]}}", + "bumpalo_3.20.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.8\"},{\"kind\":\"dev\",\"name\":\"blink-alloc\",\"req\":\"=0.4.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"=1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"=1.10.0\"},{\"kind\":\"dev\",\"name\":\"rayon-core\",\"req\":\"=1.12.1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.171\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.197\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.115\"}],\"features\":{\"allocator_api\":[],\"bench_allocator_api\":[\"allocator_api\",\"blink-alloc/nightly\"],\"boxed\":[],\"collections\":[],\"default\":[],\"serde\":[\"dep:serde\"],\"std\":[]}}", + "bytes_1.11.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"extra-platforms\",\"optional\":true,\"package\":\"portable-atomic\",\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.60\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "camino_1.2.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"name\":\"proptest\",\"optional\":true,\"req\":\"^1.0.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.223\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.8\"},{\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"proptest1\":[\"dep:proptest\"],\"serde1\":[\"dep:serde_core\"]}}", + "cc_1.2.62": "{\"dependencies\":[{\"name\":\"find-msvc-tools\",\"req\":\"^0.1.9\"},{\"default_features\":false,\"name\":\"jobserver\",\"optional\":true,\"req\":\"^0.1.30\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.62\",\"target\":\"cfg(unix)\"},{\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"jobserver\":[],\"parallel\":[\"dep:libc\",\"dep:jobserver\"]}}", + "cfg-if_1.0.4": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"rustc-dep-of-std\":[\"core\"]}}", + "chrono_0.4.44": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.0\"},{\"name\":\"defmt\",\"optional\":true,\"req\":\"^1.0.1\"},{\"features\":[\"fallback\"],\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1.45\",\"target\":\"cfg(unix)\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"name\":\"pure-rust-locales\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.43\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.99\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"similar-asserts\",\"req\":\"^1.6.1\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"windows-bindgen\",\"req\":\"^0.66\"},{\"name\":\"windows-link\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(windows)\"}],\"features\":{\"__internal_bench\":[],\"alloc\":[],\"clock\":[\"winapi\",\"iana-time-zone\",\"now\"],\"core-error\":[],\"default\":[\"clock\",\"std\",\"oldtime\",\"wasmbind\"],\"defmt\":[\"dep:defmt\",\"pure-rust-locales?/defmt\"],\"libc\":[],\"now\":[\"std\"],\"oldtime\":[],\"rkyv\":[\"dep:rkyv\",\"rkyv/size_32\"],\"rkyv-16\":[\"dep:rkyv\",\"rkyv?/size_16\"],\"rkyv-32\":[\"dep:rkyv\",\"rkyv?/size_32\"],\"rkyv-64\":[\"dep:rkyv\",\"rkyv?/size_64\"],\"rkyv-validation\":[\"rkyv?/validation\"],\"std\":[\"alloc\"],\"unstable-locales\":[\"pure-rust-locales\"],\"wasmbind\":[\"wasm-bindgen\",\"js-sys\"],\"winapi\":[\"windows-link\"]}}", + "chunked_transfer_1.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"}],\"features\":{}}", + "clap_4.6.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"clap-cargo\",\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"clap_builder\",\"req\":\"=4.6.0\"},{\"name\":\"clap_derive\",\"optional\":true,\"req\":\"=4.6.0\"},{\"kind\":\"dev\",\"name\":\"jiff\",\"req\":\"^0.2.23\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.27\"},{\"kind\":\"dev\",\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"features\":[\"term-svg\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.116\"},{\"default_features\":false,\"features\":[\"color-auto\",\"diff\",\"examples\"],\"kind\":\"dev\",\"name\":\"trycmd\",\"req\":\"^1.1.1\"}],\"features\":{\"cargo\":[\"clap_builder/cargo\"],\"color\":[\"clap_builder/color\"],\"debug\":[\"clap_builder/debug\",\"clap_derive?/debug\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[\"clap_builder/deprecated\",\"clap_derive?/deprecated\"],\"derive\":[\"dep:clap_derive\"],\"env\":[\"clap_builder/env\"],\"error-context\":[\"clap_builder/error-context\"],\"help\":[\"clap_builder/help\"],\"std\":[\"clap_builder/std\"],\"string\":[\"clap_builder/string\"],\"suggestions\":[\"clap_builder/suggestions\"],\"unicode\":[\"clap_builder/unicode\"],\"unstable-derive-ui-tests\":[],\"unstable-doc\":[\"clap_builder/unstable-doc\",\"derive\"],\"unstable-ext\":[\"clap_builder/unstable-ext\"],\"unstable-markdown\":[\"clap_derive/unstable-markdown\"],\"unstable-styles\":[\"clap_builder/unstable-styles\"],\"unstable-v5\":[\"clap_builder/unstable-v5\",\"clap_derive?/unstable-v5\",\"deprecated\"],\"usage\":[\"clap_builder/usage\"],\"wrap_help\":[\"clap_builder/wrap_help\"]}}", + "clap_4.6.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"clap-cargo\",\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"clap_builder\",\"req\":\"=4.6.0\"},{\"name\":\"clap_derive\",\"optional\":true,\"req\":\"=4.6.1\"},{\"kind\":\"dev\",\"name\":\"jiff\",\"req\":\"^0.2.23\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.22\"},{\"kind\":\"dev\",\"name\":\"semver\",\"req\":\"^1.0.27\"},{\"kind\":\"dev\",\"name\":\"shlex\",\"req\":\"^1.3.0\"},{\"features\":[\"term-svg\"],\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.116\"},{\"default_features\":false,\"features\":[\"color-auto\",\"diff\",\"examples\"],\"kind\":\"dev\",\"name\":\"trycmd\",\"req\":\"^1.2.0\"}],\"features\":{\"cargo\":[\"clap_builder/cargo\"],\"color\":[\"clap_builder/color\"],\"debug\":[\"clap_builder/debug\",\"clap_derive?/debug\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[\"clap_builder/deprecated\",\"clap_derive?/deprecated\"],\"derive\":[\"dep:clap_derive\"],\"env\":[\"clap_builder/env\"],\"error-context\":[\"clap_builder/error-context\"],\"help\":[\"clap_builder/help\"],\"std\":[\"clap_builder/std\"],\"string\":[\"clap_builder/string\"],\"suggestions\":[\"clap_builder/suggestions\"],\"unicode\":[\"clap_builder/unicode\"],\"unstable-derive-ui-tests\":[],\"unstable-doc\":[\"clap_builder/unstable-doc\",\"derive\"],\"unstable-ext\":[\"clap_builder/unstable-ext\"],\"unstable-markdown\":[\"clap_derive/unstable-markdown\"],\"unstable-styles\":[\"clap_builder/unstable-styles\"],\"unstable-v5\":[\"clap_builder/unstable-v5\",\"clap_derive?/unstable-v5\",\"deprecated\"],\"usage\":[\"clap_builder/usage\"],\"wrap_help\":[\"clap_builder/wrap_help\"]}}", + "clap_builder_4.6.0": "{\"dependencies\":[{\"name\":\"anstream\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"anstyle\",\"req\":\"^1.0.13\"},{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.76\"},{\"name\":\"clap_lex\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"color-print\",\"req\":\"^0.3.7\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"name\":\"strsim\",\"optional\":true,\"req\":\"^0.11.1\"},{\"name\":\"terminal_size\",\"optional\":true,\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"unic-emoji-char\",\"req\":\"^0.9.0\"},{\"name\":\"unicase\",\"optional\":true,\"req\":\"^2.9.0\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2.2\"}],\"features\":{\"cargo\":[],\"color\":[\"dep:anstream\"],\"debug\":[\"dep:backtrace\"],\"default\":[\"std\",\"color\",\"help\",\"usage\",\"error-context\",\"suggestions\"],\"deprecated\":[],\"env\":[],\"error-context\":[],\"help\":[],\"std\":[\"anstyle/std\"],\"string\":[],\"suggestions\":[\"dep:strsim\",\"error-context\"],\"unicode\":[\"dep:unicode-width\",\"dep:unicase\"],\"unstable-doc\":[\"cargo\",\"wrap_help\",\"env\",\"unicode\",\"string\",\"unstable-ext\"],\"unstable-ext\":[],\"unstable-styles\":[\"color\"],\"unstable-v5\":[\"deprecated\"],\"usage\":[],\"wrap_help\":[\"help\",\"dep:terminal_size\"]}}", + "clap_derive_4.6.0": "{\"dependencies\":[{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1.0.13\"},{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13.1\"},{\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.117\"}],\"features\":{\"debug\":[],\"default\":[],\"deprecated\":[],\"raw-deprecated\":[\"deprecated\"],\"unstable-markdown\":[\"dep:pulldown-cmark\",\"dep:anstyle\"],\"unstable-v5\":[\"deprecated\"]}}", + "clap_derive_4.6.1": "{\"dependencies\":[{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1.0.14\"},{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.106\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13.3\"},{\"name\":\"quote\",\"req\":\"^1.0.45\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.117\"}],\"features\":{\"debug\":[],\"default\":[],\"deprecated\":[],\"raw-deprecated\":[\"deprecated\"],\"unstable-markdown\":[\"dep:pulldown-cmark\",\"dep:anstyle\"],\"unstable-v5\":[\"deprecated\"]}}", + "clap_lex_1.1.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.16\"}],\"features\":{}}", + "colorchoice_1.0.5": "{\"dependencies\":[],\"features\":{}}", + "core-foundation-sys_0.8.7": "{\"dependencies\":[],\"features\":{\"default\":[\"link\"],\"link\":[],\"mac_os_10_7_support\":[],\"mac_os_10_8_features\":[]}}", + "crc32fast_1.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1\"},{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"nightly\":[],\"std\":[]}}", + "crossbeam-deque_0.8.6": "{\"dependencies\":[{\"default_features\":false,\"name\":\"crossbeam-epoch\",\"req\":\"^0.9.17\"},{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.18\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"crossbeam-epoch/std\",\"crossbeam-utils/std\"]}}", + "crossbeam-epoch_0.9.18": "{\"dependencies\":[{\"default_features\":false,\"name\":\"crossbeam-utils\",\"req\":\"^0.8.18\"},{\"name\":\"loom-crate\",\"optional\":true,\"package\":\"loom\",\"req\":\"^0.7.1\",\"target\":\"cfg(crossbeam_loom)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"loom\":[\"loom-crate\",\"crossbeam-utils/loom\"],\"nightly\":[\"crossbeam-utils/nightly\"],\"std\":[\"alloc\",\"crossbeam-utils/std\"]}}", + "crossbeam-utils_0.8.21": "{\"dependencies\":[{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7.1\",\"target\":\"cfg(crossbeam_loom)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"nightly\":[],\"std\":[]}}", + "deranged_0.5.8": "{\"dependencies\":[{\"name\":\"deranged-macros\",\"optional\":true,\"req\":\"=0.3.0\"},{\"default_features\":false,\"name\":\"num-traits\",\"optional\":true,\"req\":\"^0.2.15\"},{\"default_features\":false,\"name\":\"powerfmt\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"name\":\"rand010\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"rand010\",\"package\":\"rand\",\"req\":\"^0.10.0\"},{\"default_features\":false,\"name\":\"rand08\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"rand08\",\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"name\":\"rand09\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"rand09\",\"package\":\"rand\",\"req\":\"^0.9.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.86\"}],\"features\":{\"alloc\":[],\"default\":[],\"macros\":[\"dep:deranged-macros\"],\"num\":[\"dep:num-traits\"],\"powerfmt\":[\"dep:powerfmt\"],\"quickcheck\":[\"dep:quickcheck\",\"alloc\"],\"rand\":[\"rand08\",\"rand09\",\"rand010\"],\"rand010\":[\"dep:rand010\"],\"rand08\":[\"dep:rand08\"],\"rand09\":[\"dep:rand09\"],\"serde\":[\"dep:serde_core\"]}}", + "displaydoc_0.2.5": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.6.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"thiserror\",\"req\":\"^1.0.24\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "either_1.15.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.95\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[],\"use_std\":[\"std\"]}}", + "env_filter_1.0.1": "{\"dependencies\":[{\"features\":[\"std\"],\"name\":\"log\",\"req\":\"^0.4.29\"},{\"default_features\":false,\"features\":[\"std\",\"perf\"],\"name\":\"regex\",\"optional\":true,\"req\":\"^1.12.3\"},{\"kind\":\"dev\",\"name\":\"snapbox\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"regex\"],\"regex\":[\"dep:regex\"]}}", + "env_logger_0.11.10": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"wincon\"],\"name\":\"anstream\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"anstyle\",\"optional\":true,\"req\":\"^1.0.13\"},{\"default_features\":false,\"name\":\"env_filter\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"jiff\",\"optional\":true,\"req\":\"^0.2.22\"},{\"features\":[\"std\"],\"name\":\"log\",\"req\":\"^0.4.29\"}],\"features\":{\"auto-color\":[\"color\",\"anstream/auto\"],\"color\":[\"dep:anstream\",\"dep:anstyle\"],\"default\":[\"auto-color\",\"humantime\",\"regex\"],\"humantime\":[\"dep:jiff\"],\"kv\":[\"log/kv\"],\"regex\":[\"env_filter/regex\"],\"unstable-kv\":[\"kv\"]}}", + "equivalent_1.0.2": "{\"dependencies\":[],\"features\":{}}", + "errno_0.3.14": "{\"dependencies\":[{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(target_os=\\\"hermit\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(target_os=\\\"wasi\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(unix)\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Diagnostics_Debug\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"libc/std\"]}}", + "fallible-iterator_0.2.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[]}}", + "fastrand_2.3.0": "{\"dependencies\":[{\"features\":[\"js\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wyhash\",\"req\":\"^0.5\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"js\":[\"std\",\"getrandom\"],\"std\":[\"alloc\"]}}", + "fastrand_2.4.1": "{\"dependencies\":[{\"features\":[\"wasm_js\"],\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.3.4\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3.4\"},{\"features\":[\"wasm_js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3.4\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wyhash\",\"req\":\"^0.6\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"js\":[\"std\",\"getrandom\"],\"std\":[\"alloc\"]}}", + "filetime_0.2.29": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.27\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{}}", + "find-msvc-tools_0.1.9": "{\"dependencies\":[],\"features\":{}}", + "fixedbitset_0.5.7": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "flate2_1.1.9": "{\"dependencies\":[{\"name\":\"cloudflare-zlib-sys\",\"optional\":true,\"req\":\"^0.3.6\"},{\"name\":\"crc32fast\",\"optional\":true,\"req\":\"^1.2.0\"},{\"name\":\"document-features\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"libz-ng-sys\",\"optional\":true,\"req\":\"^1.1.16\"},{\"default_features\":false,\"name\":\"libz-sys\",\"optional\":true,\"req\":\"^1.1.20\"},{\"default_features\":false,\"features\":[\"with-alloc\",\"simd\"],\"name\":\"miniz_oxide\",\"req\":\"^0.8.5\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"emscripten\\\")))\"},{\"default_features\":false,\"features\":[\"with-alloc\",\"simd\"],\"name\":\"miniz_oxide\",\"optional\":true,\"req\":\"^0.8.5\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"std\",\"rust-allocator\"],\"name\":\"zlib-rs\",\"optional\":true,\"req\":\"^0.6.0\"}],\"features\":{\"any_c_zlib\":[\"any_zlib\"],\"any_impl\":[],\"any_zlib\":[\"any_impl\"],\"cloudflare_zlib\":[\"any_c_zlib\",\"cloudflare-zlib-sys\",\"dep:crc32fast\"],\"default\":[\"rust_backend\"],\"miniz-sys\":[\"rust_backend\"],\"miniz_oxide\":[\"any_impl\",\"dep:miniz_oxide\",\"dep:crc32fast\"],\"rust_backend\":[\"miniz_oxide\",\"any_impl\"],\"zlib\":[\"any_c_zlib\",\"libz-sys\",\"dep:crc32fast\"],\"zlib-default\":[\"any_c_zlib\",\"libz-sys/default\",\"dep:crc32fast\"],\"zlib-ng\":[\"any_c_zlib\",\"libz-ng-sys\",\"dep:crc32fast\"],\"zlib-ng-compat\":[\"zlib\",\"libz-sys/zlib-ng\",\"dep:crc32fast\"],\"zlib-rs\":[\"any_zlib\",\"dep:zlib-rs\"]}}", + "fnv_1.0.7": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "foldhash_0.1.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"ahash\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"hashbrown\",\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.8\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "form_urlencoded_1.2.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"percent-encoding\",\"req\":\"^2.3.0\"}],\"features\":{\"alloc\":[\"percent-encoding/alloc\"],\"default\":[\"std\"],\"std\":[\"alloc\",\"percent-encoding/std\"]}}", + "futures-channel_0.3.32": "{\"dependencies\":[{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-sink\",\"optional\":true,\"req\":\"^0.3.32\"}],\"features\":{\"alloc\":[\"futures-core/alloc\"],\"cfg-target-has-atomic\":[],\"default\":[\"std\"],\"sink\":[\"futures-sink\"],\"std\":[\"alloc\",\"futures-core/std\"],\"unstable\":[]}}", + "futures-core_0.3.32": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.3\"}],\"features\":{\"alloc\":[],\"cfg-target-has-atomic\":[],\"default\":[\"std\"],\"std\":[\"alloc\"],\"unstable\":[]}}", + "futures-sink_0.3.32": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", + "futures-task_0.3.32": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"cfg-target-has-atomic\":[],\"default\":[\"std\"],\"std\":[\"alloc\"],\"unstable\":[]}}", + "futures-util_0.3.32": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.32\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-macro\",\"optional\":true,\"req\":\"=0.3.32\"},{\"default_features\":false,\"name\":\"futures-sink\",\"optional\":true,\"req\":\"^0.3.32\"},{\"default_features\":false,\"name\":\"futures-task\",\"req\":\"^0.3.32\"},{\"name\":\"futures_01\",\"optional\":true,\"package\":\"futures\",\"req\":\"^0.1.25\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.26\"},{\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.2\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.6\"},{\"default_features\":false,\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.7\"},{\"name\":\"spin\",\"optional\":true,\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^0.1.11\"},{\"name\":\"tokio-io\",\"optional\":true,\"req\":\"^0.1.9\"}],\"features\":{\"alloc\":[\"futures-core/alloc\",\"futures-task/alloc\",\"slab\"],\"async-await\":[],\"async-await-macro\":[\"async-await\",\"futures-macro\"],\"bilock\":[],\"cfg-target-has-atomic\":[],\"channel\":[\"std\",\"futures-channel\"],\"compat\":[\"std\",\"futures_01\",\"libc\"],\"default\":[\"std\",\"async-await\",\"async-await-macro\"],\"io\":[\"std\",\"futures-io\",\"memchr\"],\"io-compat\":[\"io\",\"compat\",\"tokio-io\",\"libc\"],\"portable-atomic\":[\"futures-core/portable-atomic\"],\"sink\":[\"futures-sink\"],\"std\":[\"alloc\",\"futures-core/std\",\"futures-task/std\",\"slab/std\"],\"unstable\":[\"futures-core/unstable\",\"futures-task/unstable\"],\"write-all-vectored\":[\"io\"]}}", + "getrandom_0.2.17": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(unix)\"},{\"default_features\":false,\"name\":\"wasi\",\"req\":\"^0.11\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.62\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.18\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"}],\"features\":{\"custom\":[],\"js\":[\"wasm-bindgen\",\"js-sys\"],\"linux_disable_fallback\":[],\"rdrand\":[],\"rustc-dep-of-std\":[\"compiler_builtins\",\"core\",\"libc/rustc-dep-of-std\",\"wasi/rustc-dep-of-std\"],\"std\":[],\"test-in-browser\":[]}}", + "getrandom_0.4.2": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.77\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\"), target_feature = \\\"atomics\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"netbsd\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"solaris\\\")\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.154\",\"target\":\"cfg(target_os = \\\"vxworks\\\")\"},{\"default_features\":false,\"name\":\"r-efi\",\"req\":\"^6\",\"target\":\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\"},{\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.10.0\"},{\"default_features\":false,\"name\":\"wasip2\",\"req\":\"^1\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\"},{\"name\":\"wasip3\",\"req\":\"^0.4\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.98\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", any(target_os = \\\"unknown\\\", target_os = \\\"none\\\")))\"}],\"features\":{\"std\":[],\"sys_rng\":[\"dep:rand_core\"],\"wasm_js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"]}}", + "gimli_0.26.2": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"crossbeam\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"fallible-iterator\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"getopts\",\"req\":\"^0.2\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"memmap2\",\"req\":\"^0.5.5\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1\"},{\"features\":[\"wasm\"],\"kind\":\"dev\",\"name\":\"object\",\"req\":\"^0.29.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"test-assembler\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"typed-arena\",\"req\":\"^2\"}],\"features\":{\"default\":[\"read\",\"write\",\"std\",\"fallible-iterator\",\"endian-reader\"],\"endian-reader\":[\"read\",\"stable_deref_trait\"],\"read\":[\"read-core\"],\"read-core\":[],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"compiler_builtins\"],\"std\":[\"fallible-iterator/std\",\"stable_deref_trait/std\"],\"write\":[\"indexmap\"]}}", + "goblin_0.10.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"plain\",\"req\":\"^0.2.3\"},{\"default_features\":false,\"name\":\"scroll\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"stderrlog\",\"req\":\"^0.6.0\"}],\"features\":{\"alloc\":[\"scroll/derive\",\"log\"],\"archive\":[\"alloc\"],\"default\":[\"std\",\"elf32\",\"elf64\",\"mach32\",\"mach64\",\"pe32\",\"pe64\",\"te\",\"archive\",\"endian_fd\"],\"elf32\":[],\"elf64\":[],\"endian_fd\":[\"alloc\"],\"mach32\":[\"alloc\",\"endian_fd\",\"archive\"],\"mach64\":[\"alloc\",\"endian_fd\",\"archive\"],\"pe32\":[\"alloc\",\"endian_fd\"],\"pe64\":[\"alloc\",\"endian_fd\"],\"std\":[\"alloc\",\"scroll/std\"],\"te\":[\"alloc\",\"endian_fd\"]}}", + "h2_0.4.13": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", + "hashbrown_0.12.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.7.0\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"bumpalo\",\"optional\":true,\"req\":\"^3.5.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"ahash-compile-time-rng\":[\"ahash/compile-time-rng\"],\"default\":[\"ahash\",\"inline-more\"],\"inline-more\":[],\"nightly\":[],\"raw\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"compiler_builtins\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", + "hashbrown_0.14.5": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.8.7\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"compiler_builtins\",\"optional\":true,\"req\":\"^0.1.2\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7.42\"},{\"features\":[\"validation\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7.42\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"ahash\",\"inline-more\",\"allocator-api2\"],\"inline-more\":[],\"nightly\":[\"allocator-api2?/nightly\",\"bumpalo/allocator_api\"],\"raw\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"compiler_builtins\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", + "hashbrown_0.15.5": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.1\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.1.2\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.2\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.25\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[]}}", + "hashbrown_0.16.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(unix)\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"foldhash?/nightly\",\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[],\"serde\":[\"dep:serde_core\",\"dep:serde\"]}}", + "hashbrown_0.17.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"allocator-api2\",\"optional\":true,\"req\":\"^0.2.9\"},{\"features\":[\"allocator-api2\"],\"kind\":\"dev\",\"name\":\"bumpalo\",\"req\":\"^3.13.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"equivalent\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0.7\"},{\"default_features\":false,\"name\":\"foldhash\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(unix)\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"default-hasher\",\"inline-more\",\"allocator-api2\",\"equivalent\",\"raw-entry\"],\"default-hasher\":[\"dep:foldhash\"],\"inline-more\":[],\"nightly\":[\"foldhash?/nightly\",\"bumpalo/allocator_api\"],\"raw-entry\":[],\"rustc-dep-of-std\":[\"nightly\",\"core\",\"alloc\",\"rustc-internal-api\"],\"rustc-internal-api\":[],\"serde\":[\"dep:serde_core\",\"dep:serde\"]}}", + "heck_0.5.0": "{\"dependencies\":[],\"features\":{}}", + "hermit-abi_0.5.2": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[],\"rustc-dep-of-std\":[\"core\",\"alloc\"]}}", + "http-body-util_0.1.3": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"macros\",\"rt\",\"sync\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"}],\"features\":{\"channel\":[\"dep:tokio\"],\"default\":[],\"full\":[\"channel\"]}}", + "http-body_1.0.1": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"http\",\"req\":\"^1\"}],\"features\":{}}", + "http_1.4.0": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"itoa\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "httparse_1.10.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.5\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "httpdate_1.0.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"}],\"features\":{}}", + "hyper-timeout_0.5.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"name\":\"hyper\",\"req\":\"^1.1\"},{\"features\":[\"http1\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1\"},{\"kind\":\"dev\",\"name\":\"hyper-tls\",\"req\":\"^0.6\"},{\"features\":[\"client-legacy\",\"http1\"],\"name\":\"hyper-util\",\"req\":\"^0.1.10\"},{\"features\":[\"client-legacy\",\"http1\",\"server\",\"server-graceful\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1.10\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"name\":\"tokio\",\"req\":\"^1.35\"},{\"features\":[\"io-std\",\"io-util\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.35\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"}],\"features\":{}}", + "hyper-util_0.1.20": "{\"dependencies\":[{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"bytes\",\"req\":\"^1.7.1\"},{\"kind\":\"dev\",\"name\":\"bytes\",\"req\":\"^1\"},{\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.16\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.16\"},{\"name\":\"http\",\"req\":\"^1.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"hyper\",\"req\":\"^1.8.0\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.4.0\"},{\"name\":\"ipnet\",\"optional\":true,\"req\":\"^2.9\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.3\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.4\"},{\"kind\":\"dev\",\"name\":\"pnet_datalink\",\"req\":\"^0.35.0\",\"target\":\"cfg(any(target_os = \\\"linux\\\", target_os = \\\"macos\\\"))\"},{\"kind\":\"dev\",\"name\":\"pretty_env_logger\",\"req\":\"^0.5\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\">=0.5.9, <0.7\"},{\"name\":\"system-configuration\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"macros\",\"test-util\",\"signal\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4\"},{\"name\":\"tower-layer\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"tower-test\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"windows-registry\",\"optional\":true,\"req\":\">=0.3, <0.7\",\"target\":\"cfg(windows)\"}],\"features\":{\"__internal_happy_eyeballs_tests\":[],\"client\":[\"hyper/client\",\"tokio/net\",\"dep:tracing\",\"dep:futures-channel\",\"dep:tower-service\"],\"client-legacy\":[\"client\",\"dep:socket2\",\"tokio/sync\",\"dep:libc\",\"dep:futures-util\"],\"client-pool\":[\"client\",\"dep:futures-util\",\"dep:tower-layer\"],\"client-proxy\":[\"client\",\"dep:base64\",\"dep:ipnet\",\"dep:percent-encoding\"],\"client-proxy-system\":[\"dep:system-configuration\",\"dep:windows-registry\"],\"default\":[],\"full\":[\"client\",\"client-legacy\",\"client-pool\",\"client-proxy\",\"client-proxy-system\",\"server\",\"server-auto\",\"server-graceful\",\"service\",\"http1\",\"http2\",\"tokio\",\"tracing\"],\"http1\":[\"hyper/http1\"],\"http2\":[\"hyper/http2\"],\"server\":[\"hyper/server\"],\"server-auto\":[\"server\",\"http1\",\"http2\"],\"server-graceful\":[\"server\",\"tokio/sync\"],\"service\":[\"dep:tower-service\"],\"tokio\":[\"dep:tokio\",\"tokio/rt\",\"tokio/time\"],\"tracing\":[\"dep:tracing\"]}}", + "hyper_1.8.1": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"optional\":true,\"req\":\"^1.1.2\"},{\"name\":\"bytes\",\"req\":\"^1.2\"},{\"kind\":\"dev\",\"name\":\"form_urlencoded\",\"req\":\"^1\"},{\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3\"},{\"features\":[\"sink\"],\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\"},{\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.31\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"alloc\",\"sink\"],\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4.2\"},{\"name\":\"http\",\"req\":\"^1\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"name\":\"httparse\",\"optional\":true,\"req\":\"^1.9\"},{\"name\":\"httpdate\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"itoa\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2.4\"},{\"kind\":\"dev\",\"name\":\"pin-project-lite\",\"req\":\"^0.2.4\"},{\"name\":\"pin-utils\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"pretty_env_logger\",\"req\":\"^0.5\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"const_generics\",\"const_new\"],\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.12\"},{\"kind\":\"dev\",\"name\":\"spmc\",\"req\":\"^0.3\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"fs\",\"macros\",\"net\",\"io-std\",\"io-util\",\"rt\",\"rt-multi-thread\",\"sync\",\"time\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"tokio-util\",\"req\":\"^0.7.10\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"want\",\"optional\":true,\"req\":\"^0.3\"}],\"features\":{\"capi\":[],\"client\":[\"dep:want\",\"dep:pin-project-lite\",\"dep:smallvec\"],\"default\":[],\"ffi\":[\"dep:http-body-util\",\"dep:futures-util\"],\"full\":[\"client\",\"http1\",\"http2\",\"server\"],\"http1\":[\"dep:atomic-waker\",\"dep:futures-channel\",\"dep:futures-core\",\"dep:httparse\",\"dep:itoa\",\"dep:pin-utils\"],\"http2\":[\"dep:futures-channel\",\"dep:futures-core\",\"dep:h2\"],\"nightly\":[],\"server\":[\"dep:httpdate\",\"dep:pin-project-lite\",\"dep:smallvec\"],\"tracing\":[\"dep:tracing\"]}}", + "iana-time-zone-haiku_0.1.2": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.79\"}],\"features\":{}}", + "iana-time-zone_0.1.65": "{\"dependencies\":[{\"name\":\"android_system_properties\",\"req\":\"^0.1.5\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.1\"},{\"name\":\"core-foundation-sys\",\"req\":\"^0.8.6\",\"target\":\"cfg(target_vendor = \\\"apple\\\")\"},{\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.1\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.1\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"iana-time-zone-haiku\",\"req\":\"^0.1.1\",\"target\":\"cfg(target_os = \\\"haiku\\\")\"},{\"name\":\"js-sys\",\"req\":\"^0.3.66\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"log\",\"req\":\"^0.4.14\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.46\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"windows-core\",\"req\":\">=0.56, <=0.62\",\"target\":\"cfg(target_os = \\\"windows\\\")\"}],\"features\":{\"fallback\":[]}}", + "icu_collections_2.2.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2.3\"},{\"kind\":\"dev\",\"name\":\"iai\",\"req\":\"^0.1.1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"features\":[\"zerovec\"],\"name\":\"potential_utf\",\"req\":\"^0.1.3\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"parse\"],\"kind\":\"dev\",\"name\":\"toml\",\"req\":\"^0.8.0\"},{\"default_features\":false,\"name\":\"utf8_iter\",\"req\":\"^1.0.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"yoke\",\"req\":\"^0.8.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"zerofrom\",\"req\":\"^0.1.6\"},{\"default_features\":false,\"features\":[\"derive\",\"yoke\"],\"name\":\"zerovec\",\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"serde?/alloc\",\"zerovec/alloc\"],\"databake\":[\"dep:databake\",\"zerovec/databake\"],\"serde\":[\"dep:serde\",\"zerovec/serde\",\"potential_utf/serde\",\"alloc\"]}}", + "icu_locale_core_2.2.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2.3\"},{\"kind\":\"dev\",\"name\":\"iai\",\"req\":\"^0.1.1\"},{\"default_features\":false,\"name\":\"litemap\",\"req\":\"^0.8.0\"},{\"default_features\":false,\"features\":[\"testing\"],\"kind\":\"dev\",\"name\":\"litemap\",\"req\":\"^0.8.0\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"potential_utf\",\"req\":\"^0.1.3\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"name\":\"tinystr\",\"req\":\"^0.8.3\"},{\"default_features\":false,\"name\":\"writeable\",\"req\":\"^0.6.1\"},{\"default_features\":false,\"name\":\"zerovec\",\"optional\":true,\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"litemap/alloc\",\"tinystr/alloc\",\"writeable/alloc\",\"serde?/alloc\"],\"databake\":[\"dep:databake\",\"alloc\"],\"serde\":[\"dep:serde\",\"tinystr/serde\"],\"zerovec\":[\"dep:zerovec\",\"tinystr/zerovec\"]}}", + "icu_normalizer_2.2.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"arraystring\",\"req\":\"^0.3.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"arrayvec\",\"req\":\"^0.7.2\"},{\"kind\":\"dev\",\"name\":\"atoi\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"detone\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"harfbuzz-traits\",\"optional\":true,\"req\":\"^0.6.0\"},{\"default_features\":false,\"name\":\"icu_collections\",\"req\":\"~2.2.0\"},{\"default_features\":false,\"name\":\"icu_normalizer_data\",\"optional\":true,\"req\":\"~2.2.0\"},{\"default_features\":false,\"name\":\"icu_properties\",\"optional\":true,\"req\":\"~2.2.0\"},{\"default_features\":false,\"name\":\"icu_provider\",\"req\":\"^2.2.0\"},{\"default_features\":false,\"features\":[\"derive\",\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"smallvec\",\"req\":\"^1.10.0\"},{\"default_features\":false,\"name\":\"utf16_iter\",\"optional\":true,\"req\":\"^1.0.2\"},{\"default_features\":false,\"name\":\"utf8_iter\",\"optional\":true,\"req\":\"^1.0.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"write16\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"arrayvec\",\"smallvec\"],\"kind\":\"dev\",\"name\":\"write16\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"zerovec\",\"req\":\"^0.11.6\"}],\"features\":{\"compiled_data\":[\"dep:icu_normalizer_data\",\"icu_properties?/compiled_data\",\"icu_provider/baked\"],\"datagen\":[\"serde\",\"dep:databake\",\"icu_properties\",\"icu_collections/databake\",\"zerovec/databake\",\"icu_properties?/datagen\",\"icu_provider/export\"],\"default\":[\"compiled_data\",\"utf8_iter\",\"utf16_iter\"],\"harfbuzz_traits\":[\"dep:harfbuzz-traits\"],\"icu_properties\":[\"dep:icu_properties\"],\"serde\":[\"dep:serde\",\"icu_collections/serde\",\"zerovec/serde\",\"icu_properties?/serde\",\"icu_provider/serde\"],\"utf16_iter\":[\"dep:utf16_iter\",\"dep:write16\"],\"utf8_iter\":[\"dep:utf8_iter\"],\"write16\":[]}}", + "icu_normalizer_data_2.2.0": "{\"dependencies\":[],\"features\":{}}", + "icu_properties_2.2.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"harfbuzz-traits\",\"optional\":true,\"req\":\"^0.6.0\"},{\"default_features\":false,\"name\":\"icu_collections\",\"req\":\"~2.2.0\"},{\"default_features\":false,\"features\":[\"zerovec\"],\"name\":\"icu_locale_core\",\"req\":\"^2.2.0\"},{\"default_features\":false,\"name\":\"icu_properties_data\",\"optional\":true,\"req\":\"~2.2.0\"},{\"default_features\":false,\"name\":\"icu_provider\",\"req\":\"^2.2.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"unicode-bidi\",\"optional\":true,\"req\":\"^0.3.11\"},{\"default_features\":false,\"features\":[\"yoke\",\"zerofrom\"],\"name\":\"zerotrie\",\"req\":\"^0.2.4\"},{\"default_features\":false,\"features\":[\"derive\",\"yoke\"],\"name\":\"zerovec\",\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"zerovec/alloc\",\"icu_collections/alloc\",\"serde?/alloc\"],\"compiled_data\":[\"dep:icu_properties_data\",\"icu_provider/baked\"],\"datagen\":[\"serde\",\"dep:databake\",\"zerovec/databake\",\"icu_collections/databake\",\"icu_locale_core/databake\",\"zerotrie/databake\",\"icu_provider/export\"],\"default\":[\"compiled_data\"],\"harfbuzz_traits\":[\"dep:harfbuzz-traits\"],\"serde\":[\"dep:serde\",\"icu_locale_core/serde\",\"zerovec/serde\",\"icu_collections/serde\",\"icu_provider/serde\",\"zerotrie/serde\"],\"unicode_bidi\":[\"dep:unicode-bidi\"]}}", + "icu_properties_data_2.2.0": "{\"dependencies\":[],\"features\":{}}", + "icu_provider_2.2.0": "{\"dependencies\":[{\"name\":\"bincode\",\"optional\":true,\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2.3\"},{\"name\":\"erased-serde\",\"optional\":true,\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"icu_locale_core\",\"req\":\"^2.2.0\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"default_features\":false,\"name\":\"postcard\",\"optional\":true,\"req\":\"^1.0.3\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.45\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"optional\":true,\"req\":\"^1.2.0\"},{\"default_features\":false,\"name\":\"writeable\",\"optional\":true,\"req\":\"^0.6.1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"yoke\",\"req\":\"^0.8.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"zerofrom\",\"req\":\"^0.1.6\"},{\"default_features\":false,\"name\":\"zerotrie\",\"optional\":true,\"req\":\"^0.2.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"zerovec\",\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"icu_locale_core/alloc\",\"serde?/alloc\",\"yoke/alloc\",\"zerofrom/alloc\",\"zerovec/alloc\",\"zerotrie?/alloc\",\"dep:stable_deref_trait\",\"dep:writeable\"],\"baked\":[\"dep:zerotrie\",\"dep:writeable\"],\"deserialize_bincode_1\":[\"serde\",\"dep:bincode\",\"std\"],\"deserialize_json\":[\"serde\",\"dep:serde_json\"],\"deserialize_postcard_1\":[\"serde\",\"dep:postcard\"],\"export\":[\"serde\",\"dep:erased-serde\",\"dep:databake\",\"std\",\"sync\",\"dep:postcard\",\"zerovec/databake\"],\"logging\":[\"dep:log\"],\"serde\":[\"dep:serde\",\"yoke/serde\"],\"std\":[\"alloc\"],\"sync\":[],\"zerotrie\":[]}}", + "id-arena_2.3.0": "{\"dependencies\":[{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.0.3\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "idna_1.1.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1\"},{\"name\":\"idna_adapter\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"const_generics\"],\"name\":\"smallvec\",\"req\":\"^1.13.1\"},{\"kind\":\"dev\",\"name\":\"tester\",\"req\":\"^0.9\"},{\"name\":\"utf8_iter\",\"req\":\"^1.0.4\"}],\"features\":{\"alloc\":[],\"compiled_data\":[\"idna_adapter/compiled_data\"],\"default\":[\"std\",\"compiled_data\"],\"std\":[\"alloc\"]}}", + "idna_adapter_1.2.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"icu_normalizer\",\"req\":\"^2.2\"},{\"default_features\":false,\"name\":\"icu_properties\",\"req\":\"^2.2\"}],\"features\":{\"compiled_data\":[\"icu_normalizer/compiled_data\",\"icu_properties/compiled_data\"]}}", + "indexmap_1.9.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"raw\"],\"name\":\"hashbrown\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.4.1\"},{\"name\":\"rustc-rayon\",\"optional\":true,\"package\":\"rustc-rayon\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"}],\"features\":{\"serde-1\":[\"serde\"],\"std\":[],\"test_debug\":[],\"test_low_transition_point\":[]}}", + "indexmap_2.13.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"equivalent\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"hashbrown\",\"req\":\"^0.16.1\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde_core\",\"dep:serde\"],\"std\":[],\"test_debug\":[]}}", + "indexmap_2.14.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"borsh\",\"optional\":true,\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"equivalent\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"fnv\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"hashbrown\",\"req\":\"^0.17\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.1\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.9\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde_core\",\"dep:serde\"],\"std\":[],\"test_debug\":[]}}", + "is_terminal_polyfill_1.70.2": "{\"dependencies\":[],\"features\":{\"default\":[]}}", + "itertools_0.13.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"either\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"permutohedron\",\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.7\"}],\"features\":{\"default\":[\"use_std\"],\"use_alloc\":[],\"use_std\":[\"use_alloc\",\"either/use_std\"]}}", + "itertools_0.14.0": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"either\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"permutohedron\",\"req\":\"^0.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.7\"}],\"features\":{\"default\":[\"use_std\"],\"use_alloc\":[],\"use_std\":[\"use_alloc\",\"either/use_std\"]}}", + "itoa_1.0.17": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{}}", + "itoa_1.0.18": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{}}", + "jiff-static_0.2.23": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.93\"},{\"name\":\"quote\",\"req\":\"^1.0.38\"},{\"name\":\"syn\",\"req\":\"^2.0.98\"}],\"features\":{\"default\":[],\"perf-inline\":[],\"tz-fat\":[],\"tzdb\":[\"dep:jiff-tzdb\"]}}", + "jiff-static_0.2.24": "{\"dependencies\":[{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.93\"},{\"name\":\"quote\",\"req\":\"^1.0.38\"},{\"name\":\"syn\",\"req\":\"^2.0.98\"}],\"features\":{\"default\":[],\"perf-inline\":[],\"tz-fat\":[],\"tzdb\":[\"dep:jiff-tzdb\"]}}", + "jiff_0.2.23": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.81\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.38\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"hifitime\",\"req\":\"^3.9.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"humantime\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.39.0\"},{\"name\":\"jiff-static\",\"req\":\"=0.2.23\",\"target\":\"cfg(any())\"},{\"name\":\"jiff-static\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"jiff-tzdb-platform\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(any(windows, target_family = \\\"wasm\\\"))\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.50\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"req\":\"^1.10.0\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"name\":\"portable-atomic-util\",\"req\":\"^0.2.4\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.203\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.34\"},{\"kind\":\"dev\",\"name\":\"tabwriter\",\"req\":\"^1.4.0\"},{\"features\":[\"local-offset\",\"macros\",\"parsing\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.36\"},{\"kind\":\"dev\",\"name\":\"time-tz\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"tzfile\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5.0\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.70\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_System_Time\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"portable-atomic-util/alloc\"],\"default\":[\"std\",\"tz-system\",\"tz-fat\",\"tzdb-bundle-platform\",\"tzdb-zoneinfo\",\"tzdb-concatenated\",\"perf-inline\"],\"js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"],\"logging\":[\"dep:log\"],\"perf-inline\":[],\"serde\":[\"dep:serde_core\"],\"static\":[\"static-tz\",\"jiff-static?/tzdb\"],\"static-tz\":[\"dep:jiff-static\"],\"std\":[\"alloc\",\"log?/std\",\"serde_core?/std\"],\"tz-fat\":[\"jiff-static?/tz-fat\"],\"tz-system\":[\"std\",\"dep:windows-sys\"],\"tzdb-bundle-always\":[\"dep:jiff-tzdb\",\"alloc\"],\"tzdb-bundle-platform\":[\"dep:jiff-tzdb-platform\",\"alloc\"],\"tzdb-concatenated\":[\"std\"],\"tzdb-zoneinfo\":[\"std\"]}}", + "jiff_0.2.24": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.81\"},{\"features\":[\"serde\"],\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.38\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\"^0.10.0\"},{\"kind\":\"dev\",\"name\":\"hifitime\",\"req\":\"^3.9.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"humantime\",\"req\":\"^2.1.0\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.39.0\"},{\"name\":\"jiff-static\",\"req\":\"=0.2.24\",\"target\":\"cfg(any())\"},{\"name\":\"jiff-static\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"jiff-tzdb\",\"optional\":true,\"req\":\"^0.1.6\"},{\"name\":\"jiff-tzdb-platform\",\"optional\":true,\"req\":\"^0.1.3\",\"target\":\"cfg(any(windows, target_family = \\\"wasm\\\"))\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.50\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.21\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.21\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"req\":\"^1.10.0\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"name\":\"portable-atomic-util\",\"req\":\"^0.2.4\",\"target\":\"cfg(not(target_has_atomic = \\\"ptr\\\"))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.203\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.221\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.117\"},{\"kind\":\"dev\",\"name\":\"serde_yaml\",\"req\":\"^0.9.34\"},{\"kind\":\"dev\",\"name\":\"tabwriter\",\"req\":\"^1.4.0\"},{\"features\":[\"local-offset\",\"macros\",\"parsing\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.36\"},{\"kind\":\"dev\",\"name\":\"time-tz\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"tzfile\",\"req\":\"^0.1.3\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.5.0\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2.70\",\"target\":\"cfg(all(any(target_arch = \\\"wasm32\\\", target_arch = \\\"wasm64\\\"), target_os = \\\"unknown\\\"))\"},{\"default_features\":false,\"features\":[\"Win32_Foundation\",\"Win32_System_Time\"],\"name\":\"windows-sys\",\"optional\":true,\"req\":\">=0.52.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"portable-atomic-util/alloc\"],\"default\":[\"std\",\"tz-system\",\"tz-fat\",\"tzdb-bundle-platform\",\"tzdb-zoneinfo\",\"tzdb-concatenated\",\"perf-inline\"],\"js\":[\"dep:wasm-bindgen\",\"dep:js-sys\"],\"logging\":[\"dep:log\"],\"perf-inline\":[],\"serde\":[\"dep:serde_core\"],\"static\":[\"static-tz\",\"jiff-static?/tzdb\"],\"static-tz\":[\"dep:jiff-static\"],\"std\":[\"alloc\",\"log?/std\",\"serde_core?/std\"],\"tz-fat\":[\"jiff-static?/tz-fat\"],\"tz-system\":[\"std\",\"dep:windows-sys\"],\"tzdb-bundle-always\":[\"dep:jiff-tzdb\",\"alloc\"],\"tzdb-bundle-platform\":[\"dep:jiff-tzdb-platform\",\"alloc\"],\"tzdb-concatenated\":[\"std\"],\"tzdb-zoneinfo\":[\"std\"]}}", + "js-sys_0.3.82": "{\"dependencies\":[{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"wasm-bindgen/std\"]}}", + "jsonc-parser_0.26.2": "{\"dependencies\":[{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.6\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.0.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"unicode-width\",\"optional\":true,\"req\":\"^0.2.0\"}],\"features\":{\"cst\":[],\"error_unicode_width\":[\"unicode-width\"],\"preserve_order\":[\"indexmap\",\"serde_json/preserve_order\"],\"serde\":[\"serde_json\"]}}", + "leb128_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.1\"}],\"features\":{\"nightly\":[]}}", + "leb128fmt_0.1.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[]}}", + "libc_0.2.183": "{\"dependencies\":[{\"name\":\"rustc-std-workspace-core\",\"optional\":true,\"req\":\"^1.0.1\"}],\"features\":{\"align\":[],\"const-extern-fn\":[],\"default\":[\"std\"],\"extra_traits\":[],\"rustc-dep-of-std\":[\"align\",\"rustc-std-workspace-core\"],\"std\":[],\"use_std\":[\"std\"]}}", + "libc_0.2.186": "{\"dependencies\":[{\"name\":\"rustc-std-workspace-core\",\"optional\":true,\"req\":\"^1.0.1\"}],\"features\":{\"align\":[],\"const-extern-fn\":[],\"default\":[\"std\"],\"extra_traits\":[],\"rustc-dep-of-std\":[\"align\",\"rustc-std-workspace-core\"],\"std\":[],\"use_std\":[\"std\"]}}", + "linux-raw-sys_0.12.1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.100\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"auxvec\":[],\"bootparam\":[],\"btrfs\":[],\"default\":[\"std\",\"general\",\"errno\"],\"elf\":[],\"elf_uapi\":[],\"errno\":[],\"general\":[],\"if_arp\":[],\"if_ether\":[],\"if_packet\":[],\"if_tun\":[],\"image\":[],\"io_uring\":[],\"ioctl\":[],\"landlock\":[],\"loop_device\":[],\"mempolicy\":[],\"net\":[],\"netlink\":[],\"no_std\":[],\"prctl\":[],\"ptrace\":[],\"rustc-dep-of-std\":[\"core\",\"no_std\"],\"std\":[],\"system\":[],\"vm_sockets\":[],\"xdp\":[]}}", + "litemap_0.8.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"features\":[\"validation\"],\"kind\":\"dev\",\"name\":\"rkyv\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.2\"}],\"features\":{\"alloc\":[],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde_core\",\"alloc\"],\"testing\":[\"alloc\"],\"yoke\":[\"dep:yoke\"]}}", + "lock_api_0.4.14": "{\"dependencies\":[{\"name\":\"owning_ref\",\"optional\":true,\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"scopeguard\",\"req\":\"^1.1.0\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.126\"}],\"features\":{\"arc_lock\":[],\"atomic_usize\":[],\"default\":[\"atomic_usize\"],\"nightly\":[]}}", + "log_0.4.29": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.63\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"sval\",\"optional\":true,\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval\",\"req\":\"^2.16\"},{\"kind\":\"dev\",\"name\":\"sval_derive\",\"req\":\"^2.16\"},{\"default_features\":false,\"name\":\"sval_ref\",\"optional\":true,\"req\":\"^2.16\"},{\"default_features\":false,\"features\":[\"inline-i128\"],\"name\":\"value-bag\",\"optional\":true,\"req\":\"^1.12\"},{\"features\":[\"test\"],\"kind\":\"dev\",\"name\":\"value-bag\",\"req\":\"^1.12\"}],\"features\":{\"kv\":[],\"kv_serde\":[\"kv_std\",\"value-bag/serde\",\"serde\"],\"kv_std\":[\"std\",\"kv\",\"value-bag/error\"],\"kv_sval\":[\"kv\",\"value-bag/sval\",\"sval\",\"sval_ref\"],\"kv_unstable\":[\"kv\",\"value-bag\"],\"kv_unstable_serde\":[\"kv_serde\",\"kv_unstable_std\"],\"kv_unstable_std\":[\"kv_std\",\"kv_unstable\"],\"kv_unstable_sval\":[\"kv_sval\",\"kv_unstable\"],\"max_level_debug\":[],\"max_level_error\":[],\"max_level_info\":[],\"max_level_off\":[],\"max_level_trace\":[],\"max_level_warn\":[],\"release_max_level_debug\":[],\"release_max_level_error\":[],\"release_max_level_info\":[],\"release_max_level_off\":[],\"release_max_level_trace\":[],\"release_max_level_warn\":[],\"serde\":[\"serde_core\"],\"std\":[]}}", + "matchit_0.8.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"actix-router\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.4\"},{\"kind\":\"dev\",\"name\":\"gonzales\",\"req\":\"^0.0.3-beta\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"path-tree\",\"req\":\"^0.2.2\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.5.4\"},{\"kind\":\"dev\",\"name\":\"route-recognizer\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"routefinder\",\"req\":\"^0.5.2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"make\",\"util\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.4\"}],\"features\":{\"__test_helpers\":[],\"default\":[]}}", + "memchr_2.8.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"libc\":[],\"logging\":[\"dep:log\"],\"rustc-dep-of-std\":[\"core\"],\"std\":[\"alloc\"],\"use_std\":[\"std\"]}}", + "mime_0.3.17": "{\"dependencies\":[],\"features\":{}}", + "mime_guess_2.0.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"name\":\"mime\",\"req\":\"^0.3\"},{\"name\":\"unicase\",\"req\":\"^2.4.0\"},{\"kind\":\"build\",\"name\":\"unicase\",\"req\":\"^2.4.0\"}],\"features\":{\"default\":[\"rev-mappings\"],\"rev-mappings\":[]}}", + "minicov_0.3.8": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.0.77\"},{\"kind\":\"build\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"]}}", + "miniz_oxide_0.8.9": "{\"dependencies\":[{\"default_features\":false,\"name\":\"adler2\",\"req\":\"^2.0\"},{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"simd-adler32\",\"optional\":true,\"req\":\"^0.3.3\"}],\"features\":{\"block-boundary\":[],\"default\":[\"with-alloc\"],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"adler2/rustc-dep-of-std\"],\"simd\":[\"simd-adler32\"],\"std\":[],\"with-alloc\":[]}}", + "mio_1.1.1": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"libc\",\"req\":\"^0.2.178\",\"target\":\"cfg(target_os = \\\"hermit\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.178\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.178\",\"target\":\"cfg(unix)\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"name\":\"wasi\",\"req\":\"^0.11.0\",\"target\":\"cfg(target_os = \\\"wasi\\\")\"},{\"features\":[\"Wdk_Foundation\",\"Wdk_Storage_FileSystem\",\"Wdk_System_IO\",\"Win32_Foundation\",\"Win32_Networking_WinSock\",\"Win32_Storage_FileSystem\",\"Win32_Security\",\"Win32_System_IO\",\"Win32_System_WindowsProgramming\"],\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"log\"],\"net\":[],\"os-ext\":[\"os-poll\",\"windows-sys/Win32_System_Pipes\",\"windows-sys/Win32_Security\"],\"os-poll\":[]}}", + "multimap_0.10.1": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"serde_impl\"],\"serde_impl\":[\"serde\"]}}", + "multipart_0.18.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"buf_redux\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"clippy\",\"optional\":true,\"req\":\">=0.0, <0.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.5\"},{\"name\":\"httparse\",\"optional\":true,\"req\":\"^1.2\"},{\"default_features\":false,\"name\":\"hyper\",\"optional\":true,\"req\":\">=0.9, <0.11\"},{\"name\":\"iron\",\"optional\":true,\"req\":\">=0.4, <0.7\"},{\"name\":\"lazy_static\",\"optional\":true,\"req\":\"^1.2.0\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"mime\",\"req\":\"^0.3.14\"},{\"name\":\"mime_guess\",\"req\":\"^2.0.1\"},{\"name\":\"nickel\",\"optional\":true,\"req\":\">=0.10.1\"},{\"name\":\"quick-error\",\"optional\":true,\"req\":\"^1.2\"},{\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"rocket\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"safemem\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"tempfile\",\"req\":\"^3\"},{\"name\":\"tiny_http\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"twoway\",\"optional\":true,\"req\":\"^0.1\"}],\"features\":{\"bench\":[],\"client\":[],\"default\":[\"client\",\"hyper\",\"iron\",\"mock\",\"nickel\",\"server\",\"tiny_http\"],\"mock\":[],\"nightly\":[],\"server\":[\"buf_redux\",\"httparse\",\"quick-error\",\"safemem\",\"twoway\"]}}", + "num-conv_0.2.1": "{\"dependencies\":[],\"features\":{}}", + "num-traits_0.2.19": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"autocfg\",\"req\":\"^1\"},{\"name\":\"libm\",\"optional\":true,\"req\":\"^0.2.0\"}],\"features\":{\"default\":[\"std\"],\"i128\":[],\"libm\":[\"dep:libm\"],\"std\":[]}}", + "num_cpus_1.17.0": "{\"dependencies\":[{\"name\":\"hermit-abi\",\"req\":\"^0.5.0\",\"target\":\"cfg(target_os = \\\"hermit\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.26\",\"target\":\"cfg(not(windows))\"}],\"features\":{}}", + "num_threads_0.1.7": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.107\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\"))\"}],\"features\":{}}", + "once_cell_1.21.4": "{\"dependencies\":[{\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1.1.3\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"critical-section\",\"req\":\"^1.1.3\"},{\"default_features\":false,\"name\":\"parking_lot_core\",\"optional\":true,\"req\":\"^0.9.10\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.10.6\"}],\"features\":{\"alloc\":[\"race\"],\"atomic-polyfill\":[\"critical-section\"],\"critical-section\":[\"dep:critical-section\",\"portable-atomic\"],\"default\":[\"std\"],\"parking_lot\":[\"dep:parking_lot_core\"],\"portable-atomic\":[\"dep:portable-atomic\"],\"race\":[],\"std\":[\"alloc\"],\"unstable\":[]}}", + "once_cell_polyfill_1.70.2": "{\"dependencies\":[],\"features\":{\"default\":[]}}", + "parking_lot_0.12.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"name\":\"lock_api\",\"req\":\"^0.4.14\"},{\"name\":\"parking_lot_core\",\"req\":\"^0.9.12\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"}],\"features\":{\"arc_lock\":[\"lock_api/arc_lock\"],\"deadlock_detection\":[\"parking_lot_core/deadlock_detection\"],\"default\":[],\"hardware-lock-elision\":[],\"nightly\":[\"parking_lot_core/nightly\",\"lock_api/nightly\"],\"owning_ref\":[\"lock_api/owning_ref\"],\"send_guard\":[],\"serde\":[\"lock_api/serde\"]}}", + "parking_lot_core_0.9.12": "{\"dependencies\":[{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.60\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.95\",\"target\":\"cfg(unix)\"},{\"name\":\"petgraph\",\"optional\":true,\"req\":\"^0.6.0\"},{\"name\":\"redox_syscall\",\"req\":\"^0.5\",\"target\":\"cfg(target_os = \\\"redox\\\")\"},{\"name\":\"smallvec\",\"req\":\"^1.6.1\"},{\"name\":\"windows-link\",\"req\":\"^0.2.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"deadlock_detection\":[\"petgraph\",\"backtrace\"],\"nightly\":[]}}", + "percent-encoding_2.3.2": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", + "petgraph_0.8.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"ahash\",\"req\":\"^0.7.2\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"kind\":\"dev\",\"name\":\"defmac\",\"req\":\"^0.2.1\"},{\"name\":\"dot-parser\",\"optional\":true,\"req\":\"^0.5.1\"},{\"name\":\"dot-parser-macros\",\"optional\":true,\"req\":\"^0.5.1\"},{\"default_features\":false,\"name\":\"fixedbitset\",\"req\":\"^0.5.7\"},{\"kind\":\"dev\",\"name\":\"fxhash\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"req\":\"^0.15.0\"},{\"default_features\":false,\"name\":\"indexmap\",\"req\":\"^2.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.12.1\"},{\"kind\":\"dev\",\"name\":\"odds\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.5.5\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.5.3\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"all\":[\"unstable\",\"quickcheck\",\"matrix_graph\",\"stable_graph\",\"graphmap\",\"rayon\",\"dot_parser\"],\"default\":[\"std\",\"graphmap\",\"stable_graph\",\"matrix_graph\"],\"dot_parser\":[\"std\",\"dep:dot-parser\",\"dep:dot-parser-macros\"],\"generate\":[],\"graphmap\":[],\"matrix_graph\":[],\"quickcheck\":[\"std\",\"dep:quickcheck\",\"graphmap\",\"stable_graph\"],\"rayon\":[\"std\",\"dep:rayon\",\"indexmap/rayon\",\"hashbrown/rayon\"],\"serde-1\":[\"serde\",\"serde_derive\"],\"stable_graph\":[\"serde?/alloc\"],\"std\":[\"indexmap/std\"],\"unstable\":[\"generate\"]}}", + "pin-project-internal_1.1.11": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1.0.25\"},{\"default_features\":false,\"features\":[\"parsing\",\"printing\",\"clone-impls\",\"proc-macro\",\"full\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.1\"}],\"features\":{}}", + "pin-project-lite_0.2.17": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"}],\"features\":{}}", + "pin-project_1.1.11": "{\"dependencies\":[{\"name\":\"pin-project-internal\",\"req\":\"=1.1.11\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"}],\"features\":{}}", + "pin-utils_0.1.0": "{\"dependencies\":[],\"features\":{}}", + "plain_0.2.3": "{\"dependencies\":[],\"features\":{}}", + "portable-atomic-util_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"build-context\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"req\":\"^1.5.1\"}],\"features\":{\"alloc\":[],\"default\":[],\"std\":[\"alloc\"]}}", + "portable-atomic-util_0.2.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"build-context\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"require-cas\"],\"name\":\"portable-atomic\",\"req\":\"^1.5.1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.60\"}],\"features\":{\"alloc\":[],\"default\":[],\"std\":[\"alloc\"]}}", + "portable-atomic_1.13.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"build-context\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"crabgrind\",\"req\":\"^0.1\",\"target\":\"cfg(valgrind)\"},{\"name\":\"critical-section\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"crossbeam-utils\",\"req\":\"=0.8.16\"},{\"kind\":\"dev\",\"name\":\"fastrand\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"=0.2.163\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.60\"},{\"kind\":\"dev\",\"name\":\"sptr\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Threading\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"fallback\"],\"disable-fiq\":[],\"fallback\":[],\"float\":[],\"force-amo\":[],\"require-cas\":[],\"s-mode\":[],\"std\":[],\"unsafe-assume-privileged\":[],\"unsafe-assume-single-core\":[]}}", + "potential_utf_0.1.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"name\":\"writeable\",\"optional\":true,\"req\":\"^0.6.1\"},{\"default_features\":false,\"name\":\"zerovec\",\"optional\":true,\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"writeable/alloc\",\"zerovec?/alloc\"],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde_core\"],\"writeable\":[\"dep:writeable\"],\"zerovec\":[\"dep:zerovec\"]}}", + "powerfmt_0.2.0": "{\"dependencies\":[{\"name\":\"powerfmt-macros\",\"optional\":true,\"req\":\"=0.1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"macros\"],\"macros\":[\"dep:powerfmt-macros\"],\"std\":[\"alloc\"]}}", + "ppv-lite86_0.2.21": "{\"dependencies\":[{\"features\":[\"simd\"],\"name\":\"zerocopy\",\"req\":\"^0.8.23\"}],\"features\":{\"default\":[\"std\"],\"no_simd\":[],\"simd\":[],\"std\":[]}}", + "prettyplease_0.2.37": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"default_features\":false,\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.105\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"extra-traits\",\"parsing\",\"printing\",\"visit-mut\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.105\"}],\"features\":{\"verbatim\":[\"syn/parsing\"]}}", + "proc-macro2_1.0.106": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tar\",\"req\":\"^0.4\"},{\"name\":\"unicode-ident\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"proc-macro\"],\"nightly\":[],\"proc-macro\":[],\"span-locations\":[]}}", + "prost-build_0.14.3": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"heck\",\"req\":\">=0.4, <=0.5\"},{\"default_features\":false,\"features\":[\"use_alloc\"],\"name\":\"itertools\",\"req\":\">=0.10, <=0.14\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"name\":\"multimap\",\"req\":\">=0.8, <=0.10\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"petgraph\",\"req\":\"^0.8\"},{\"name\":\"prettyplease\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"prost\",\"req\":\"^0.14.3\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.3\"},{\"default_features\":false,\"name\":\"pulldown-cmark\",\"optional\":true,\"req\":\"^0.13\"},{\"name\":\"pulldown-cmark-to-cmark\",\"optional\":true,\"req\":\"^22\"},{\"default_features\":false,\"features\":[\"std\",\"unicode-bool\"],\"name\":\"regex\",\"req\":\"^1.8.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"cleanup-markdown\":[\"dep:pulldown-cmark\",\"dep:pulldown-cmark-to-cmark\"],\"default\":[\"format\"],\"format\":[\"dep:prettyplease\",\"dep:syn\"]}}", + "prost-derive_0.14.3": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.1\"},{\"name\":\"itertools\",\"req\":\">=0.10.1, <=0.14\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", + "prost-types_0.14.3": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.4\"},{\"default_features\":false,\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.34\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"prost\",\"req\":\"^0.14.3\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\"],\"std\":[\"prost/std\"]}}", + "prost_0.14.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"name\":\"prost-derive\",\"optional\":true,\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"}],\"features\":{\"default\":[\"derive\",\"std\"],\"derive\":[\"dep:prost-derive\"],\"no-recursion-limit\":[],\"std\":[]}}", + "protoc-gen-prost_0.5.0": "{\"dependencies\":[{\"name\":\"once_cell\",\"req\":\"^1.21.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"prost\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-build\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"regex\",\"req\":\"^1.11.1\"}],\"features\":{}}", + "protoc-gen-tonic_0.5.0": "{\"dependencies\":[{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"prettyplease\",\"req\":\"^0.2.37\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.103\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"prost\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-build\",\"req\":\"^0.14.1\"},{\"default_features\":false,\"name\":\"prost-types\",\"req\":\"^0.14.1\"},{\"name\":\"protoc-gen-prost\",\"req\":\"^0.5.0\"},{\"name\":\"quote\",\"req\":\"^1.0.42\"},{\"default_features\":false,\"name\":\"regex\",\"req\":\"^1.11.1\"},{\"features\":[\"parsing\",\"full\"],\"name\":\"syn\",\"req\":\"^2.0.109\"},{\"name\":\"tonic-build\",\"req\":\"^0.14.1\"}],\"features\":{}}", + "pyo3-build-config_0.28.3": "{\"dependencies\":[{\"name\":\"python3-dll-a\",\"optional\":true,\"req\":\"^0.2.12\"},{\"kind\":\"build\",\"name\":\"python3-dll-a\",\"optional\":true,\"req\":\"^0.2.12\"},{\"name\":\"target-lexicon\",\"req\":\"^0.13.3\"},{\"kind\":\"build\",\"name\":\"target-lexicon\",\"req\":\"^0.13.3\"}],\"features\":{\"abi3\":[],\"abi3-py310\":[\"abi3-py311\"],\"abi3-py311\":[\"abi3-py312\"],\"abi3-py312\":[\"abi3-py313\"],\"abi3-py313\":[\"abi3-py314\"],\"abi3-py314\":[\"abi3\"],\"abi3-py37\":[\"abi3-py38\"],\"abi3-py38\":[\"abi3-py39\"],\"abi3-py39\":[\"abi3-py310\"],\"default\":[],\"extension-module\":[],\"generate-import-lib\":[\"dep:python3-dll-a\"],\"resolve-config\":[]}}", + "pyo3-ffi_0.28.3": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.62\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\"},{\"features\":[\"resolve-config\"],\"kind\":\"build\",\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"}],\"features\":{\"abi3\":[\"pyo3-build-config/abi3\"],\"abi3-py310\":[\"abi3-py311\",\"pyo3-build-config/abi3-py310\"],\"abi3-py311\":[\"abi3-py312\",\"pyo3-build-config/abi3-py311\"],\"abi3-py312\":[\"abi3-py313\",\"pyo3-build-config/abi3-py312\"],\"abi3-py313\":[\"abi3-py314\",\"pyo3-build-config/abi3-py313\"],\"abi3-py314\":[\"abi3\",\"pyo3-build-config/abi3-py314\"],\"abi3-py37\":[\"abi3-py38\",\"pyo3-build-config/abi3-py37\"],\"abi3-py38\":[\"abi3-py39\",\"pyo3-build-config/abi3-py38\"],\"abi3-py39\":[\"abi3-py310\",\"pyo3-build-config/abi3-py39\"],\"default\":[],\"extension-module\":[\"pyo3-build-config/extension-module\"],\"generate-import-lib\":[\"pyo3-build-config/generate-import-lib\"]}}", + "pyo3-introspection_0.28.3": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1\"},{\"name\":\"goblin\",\"req\":\">=0.9, <0.11\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.12.0\"}],\"features\":{}}", + "pyo3-macros-backend_0.28.3": "{\"dependencies\":[{\"name\":\"heck\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"features\":[\"resolve-config\"],\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"},{\"kind\":\"build\",\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0.37\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"full\",\"extra-traits\",\"visit-mut\"],\"name\":\"syn\",\"req\":\"^2.0.59\"}],\"features\":{\"experimental-async\":[],\"experimental-inspect\":[]}}", + "pyo3-macros_0.28.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"pyo3-macros-backend\",\"req\":\"=0.28.3\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{\"experimental-async\":[\"pyo3-macros-backend/experimental-async\"],\"experimental-inspect\":[\"pyo3-macros-backend/experimental-inspect\"],\"multiple-pymethods\":[]}}", + "pyo3_0.28.3": "{\"dependencies\":[{\"name\":\"anyhow\",\"optional\":true,\"req\":\"^1.0.1\"},{\"kind\":\"dev\",\"name\":\"assert_approx_eq\",\"req\":\"^1.1.0\"},{\"name\":\"bigdecimal\",\"optional\":true,\"req\":\"^0.4.7\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.10\"},{\"default_features\":false,\"name\":\"chrono\",\"optional\":true,\"req\":\"^0.4.25\"},{\"kind\":\"dev\",\"name\":\"chrono\",\"req\":\"^0.4.25\"},{\"default_features\":false,\"name\":\"chrono-tz\",\"optional\":true,\"req\":\">=0.10, <0.11\"},{\"kind\":\"dev\",\"name\":\"chrono-tz\",\"req\":\">=0.10, <0.11\"},{\"name\":\"either\",\"optional\":true,\"req\":\"^1.9\"},{\"name\":\"eyre\",\"optional\":true,\"req\":\">=0.6.8, <0.7\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.28\"},{\"default_features\":false,\"name\":\"hashbrown\",\"optional\":true,\"req\":\">=0.15.0, <0.17\"},{\"features\":[\"fallback\"],\"name\":\"iana-time-zone\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\">=2.5.0, <3\"},{\"name\":\"inventory\",\"optional\":true,\"req\":\"^0.3.5\"},{\"name\":\"jiff-02\",\"optional\":true,\"package\":\"jiff\",\"req\":\"^0.2\"},{\"name\":\"libc\",\"req\":\"^0.2.62\"},{\"name\":\"lock_api\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"num-bigint\",\"optional\":true,\"req\":\"^0.4.4\"},{\"name\":\"num-complex\",\"optional\":true,\"req\":\">=0.4.6, <0.5\"},{\"name\":\"num-rational\",\"optional\":true,\"req\":\"^0.4.1\"},{\"name\":\"num-traits\",\"optional\":true,\"req\":\"^0.2.16\"},{\"name\":\"once_cell\",\"req\":\"^1.21\"},{\"default_features\":false,\"name\":\"ordered-float\",\"optional\":true,\"req\":\"^5.0.0\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12\"},{\"features\":[\"arc_lock\"],\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"^0.12.3\"},{\"name\":\"portable-atomic\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_has_atomic = \\\"64\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1.0\"},{\"features\":[\"resolve-config\"],\"kind\":\"build\",\"name\":\"pyo3-build-config\",\"req\":\"=0.28.3\"},{\"name\":\"pyo3-ffi\",\"req\":\"=0.28.3\"},{\"name\":\"pyo3-macros\",\"optional\":true,\"req\":\"=0.28.3\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.6.1\"},{\"default_features\":false,\"name\":\"rust_decimal\",\"optional\":true,\"req\":\"^1.15\"},{\"kind\":\"dev\",\"name\":\"send_wrapper\",\"req\":\"^0.6\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.61\"},{\"name\":\"smallvec\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.12.0\"},{\"default_features\":false,\"name\":\"time\",\"optional\":true,\"req\":\"^0.3.38\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\">=1.0.115\"},{\"name\":\"uuid\",\"optional\":true,\"req\":\"^1.12.0\"},{\"features\":[\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.10.0\"}],\"features\":{\"abi3\":[\"pyo3-build-config/abi3\",\"pyo3-ffi/abi3\"],\"abi3-py310\":[\"abi3-py311\",\"pyo3-build-config/abi3-py310\",\"pyo3-ffi/abi3-py310\"],\"abi3-py311\":[\"abi3-py312\",\"pyo3-build-config/abi3-py311\",\"pyo3-ffi/abi3-py311\"],\"abi3-py312\":[\"abi3-py313\",\"pyo3-build-config/abi3-py312\",\"pyo3-ffi/abi3-py312\"],\"abi3-py313\":[\"abi3-py314\",\"pyo3-build-config/abi3-py313\",\"pyo3-ffi/abi3-py313\"],\"abi3-py314\":[\"abi3\",\"pyo3-build-config/abi3-py314\",\"pyo3-ffi/abi3-py314\"],\"abi3-py37\":[\"abi3-py38\",\"pyo3-build-config/abi3-py37\",\"pyo3-ffi/abi3-py37\"],\"abi3-py38\":[\"abi3-py39\",\"pyo3-build-config/abi3-py38\",\"pyo3-ffi/abi3-py38\"],\"abi3-py39\":[\"abi3-py310\",\"pyo3-build-config/abi3-py39\",\"pyo3-ffi/abi3-py39\"],\"arc_lock\":[\"lock_api\",\"lock_api/arc_lock\",\"parking_lot?/arc_lock\"],\"auto-initialize\":[],\"bigdecimal\":[\"dep:bigdecimal\",\"num-bigint\"],\"chrono-local\":[\"chrono/clock\",\"dep:iana-time-zone\"],\"default\":[\"macros\"],\"experimental-async\":[\"macros\",\"pyo3-macros/experimental-async\"],\"experimental-inspect\":[\"pyo3-macros/experimental-inspect\"],\"extension-module\":[\"pyo3-ffi/extension-module\"],\"full\":[\"macros\",\"anyhow\",\"arc_lock\",\"bigdecimal\",\"bytes\",\"chrono\",\"chrono-local\",\"chrono-tz\",\"either\",\"experimental-async\",\"experimental-inspect\",\"eyre\",\"hashbrown\",\"indexmap\",\"jiff-02\",\"lock_api\",\"num-bigint\",\"num-complex\",\"num-rational\",\"ordered-float\",\"parking_lot\",\"py-clone\",\"rust_decimal\",\"serde\",\"smallvec\",\"time\",\"uuid\"],\"generate-import-lib\":[\"pyo3-ffi/generate-import-lib\"],\"macros\":[\"pyo3-macros\"],\"multiple-pymethods\":[\"inventory\",\"pyo3-macros/multiple-pymethods\"],\"nightly\":[],\"num-bigint\":[\"dep:num-bigint\",\"dep:num-traits\"],\"parking_lot\":[\"dep:parking_lot\",\"lock_api\"],\"py-clone\":[]}}", + "quick-error_1.2.3": "{\"dependencies\":[],\"features\":{}}", + "quote_1.0.45": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"default\":[\"proc-macro\"],\"proc-macro\":[\"proc-macro2/proc-macro\"]}}", + "r-efi_6.0.0": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"native\":[],\"rustc-dep-of-std\":[\"core\"]}}", + "rand_0.8.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.2.1\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.22\",\"target\":\"cfg(unix)\"},{\"default_features\":false,\"name\":\"rand_chacha\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"rand_core\",\"req\":\"^0.6.0\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.3.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.103\"}],\"features\":{\"alloc\":[\"rand_core/alloc\"],\"default\":[\"std\",\"std_rng\"],\"getrandom\":[\"rand_core/getrandom\"],\"log\":[],\"min_const_gen\":[],\"nightly\":[],\"serde1\":[\"serde\",\"rand_core/serde1\"],\"small_rng\":[],\"std\":[\"rand_core/std\",\"rand_chacha/std\",\"alloc\",\"getrandom\",\"libc\"],\"std_rng\":[\"rand_chacha\"]}}", + "rand_chacha_0.3.1": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"simd\"],\"name\":\"ppv-lite86\",\"req\":\"^0.2.8\"},{\"name\":\"rand_core\",\"req\":\"^0.6.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"serde1\":[\"serde\"],\"simd\":[],\"std\":[\"ppv-lite86/std\"]}}", + "rand_core_0.6.4": "{\"dependencies\":[{\"name\":\"getrandom\",\"optional\":true,\"req\":\"^0.2\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[],\"serde1\":[\"serde\"],\"std\":[\"alloc\",\"getrandom\",\"getrandom/std\"]}}", + "rayon-core_1.13.0": "{\"dependencies\":[{\"name\":\"crossbeam-deque\",\"req\":\"^0.8.1\"},{\"name\":\"crossbeam-utils\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"scoped-tls\",\"req\":\"^1.0\"},{\"name\":\"wasm_sync\",\"optional\":true,\"req\":\"^0.1.0\"}],\"features\":{\"web_spin_lock\":[\"dep:wasm_sync\"]}}", + "rayon_1.12.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"either\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.4\"},{\"name\":\"rayon-core\",\"req\":\"^1.13.0\"},{\"name\":\"wasm_sync\",\"optional\":true,\"req\":\"^0.1.0\"}],\"features\":{\"web_spin_lock\":[\"dep:wasm_sync\",\"rayon-core/web_spin_lock\"]}}", + "redox_syscall_0.5.18": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.4\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"}],\"features\":{\"default\":[\"userspace\"],\"rustc-dep-of-std\":[\"core\",\"bitflags/rustc-dep-of-std\"],\"std\":[],\"userspace\":[]}}", + "regex-automata_0.4.14": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aho-corasick\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.69\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"bstr\",\"req\":\"^1.3.0\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.3\"},{\"default_features\":false,\"features\":[\"atty\",\"humantime\",\"termcolor\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.9.3\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.14\"},{\"default_features\":false,\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.6.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"name\":\"regex-syntax\",\"optional\":true,\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex-test\",\"req\":\"^0.1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"syntax\",\"perf\",\"unicode\",\"meta\",\"nfa\",\"dfa\",\"hybrid\"],\"dfa\":[\"dfa-build\",\"dfa-search\",\"dfa-onepass\"],\"dfa-build\":[\"nfa-thompson\",\"dfa-search\"],\"dfa-onepass\":[\"nfa-thompson\"],\"dfa-search\":[],\"hybrid\":[\"alloc\",\"nfa-thompson\"],\"internal-instrument\":[\"internal-instrument-pikevm\"],\"internal-instrument-pikevm\":[\"logging\",\"std\"],\"logging\":[\"dep:log\",\"aho-corasick?/logging\",\"memchr?/logging\"],\"meta\":[\"syntax\",\"nfa-pikevm\"],\"nfa\":[\"nfa-thompson\",\"nfa-pikevm\",\"nfa-backtrack\"],\"nfa-backtrack\":[\"nfa-thompson\"],\"nfa-pikevm\":[\"nfa-thompson\"],\"nfa-thompson\":[\"alloc\"],\"perf\":[\"perf-inline\",\"perf-literal\"],\"perf-inline\":[],\"perf-literal\":[\"perf-literal-substring\",\"perf-literal-multisubstring\"],\"perf-literal-multisubstring\":[\"dep:aho-corasick\"],\"perf-literal-substring\":[\"aho-corasick?/perf-literal\",\"dep:memchr\"],\"std\":[\"regex-syntax?/std\",\"memchr?/std\",\"aho-corasick?/std\",\"alloc\"],\"syntax\":[\"dep:regex-syntax\",\"alloc\"],\"unicode\":[\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"unicode-word-boundary\",\"regex-syntax?/unicode\"],\"unicode-age\":[\"regex-syntax?/unicode-age\"],\"unicode-bool\":[\"regex-syntax?/unicode-bool\"],\"unicode-case\":[\"regex-syntax?/unicode-case\"],\"unicode-gencat\":[\"regex-syntax?/unicode-gencat\"],\"unicode-perl\":[\"regex-syntax?/unicode-perl\"],\"unicode-script\":[\"regex-syntax?/unicode-script\"],\"unicode-segment\":[\"regex-syntax?/unicode-segment\"],\"unicode-word-boundary\":[]}}", + "regex-syntax_0.8.10": "{\"dependencies\":[{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.3.0\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\",\"unicode\"],\"std\":[],\"unicode\":[\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"unicode-age\":[],\"unicode-bool\":[],\"unicode-case\":[],\"unicode-gencat\":[],\"unicode-perl\":[],\"unicode-script\":[],\"unicode-segment\":[]}}", + "regex_1.12.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aho-corasick\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.69\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"atty\",\"humantime\",\"termcolor\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.9.3\"},{\"default_features\":false,\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.6.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"features\":[\"alloc\",\"syntax\",\"meta\",\"nfa-pikevm\"],\"name\":\"regex-automata\",\"req\":\"^0.4.12\"},{\"default_features\":false,\"name\":\"regex-syntax\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex-test\",\"req\":\"^0.1.0\"}],\"features\":{\"default\":[\"std\",\"perf\",\"unicode\",\"regex-syntax/default\"],\"logging\":[\"aho-corasick?/logging\",\"memchr?/logging\",\"regex-automata/logging\"],\"pattern\":[],\"perf\":[\"perf-cache\",\"perf-dfa\",\"perf-onepass\",\"perf-backtrack\",\"perf-inline\",\"perf-literal\"],\"perf-backtrack\":[\"regex-automata/nfa-backtrack\"],\"perf-cache\":[],\"perf-dfa\":[\"regex-automata/hybrid\"],\"perf-dfa-full\":[\"regex-automata/dfa-build\",\"regex-automata/dfa-search\"],\"perf-inline\":[\"regex-automata/perf-inline\"],\"perf-literal\":[\"dep:aho-corasick\",\"dep:memchr\",\"regex-automata/perf-literal\"],\"perf-onepass\":[\"regex-automata/dfa-onepass\"],\"std\":[\"aho-corasick?/std\",\"memchr?/std\",\"regex-automata/std\",\"regex-syntax/std\"],\"unicode\":[\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"regex-automata/unicode\",\"regex-syntax/unicode\"],\"unicode-age\":[\"regex-automata/unicode-age\",\"regex-syntax/unicode-age\"],\"unicode-bool\":[\"regex-automata/unicode-bool\",\"regex-syntax/unicode-bool\"],\"unicode-case\":[\"regex-automata/unicode-case\",\"regex-syntax/unicode-case\"],\"unicode-gencat\":[\"regex-automata/unicode-gencat\",\"regex-syntax/unicode-gencat\"],\"unicode-perl\":[\"regex-automata/unicode-perl\",\"regex-automata/unicode-word-boundary\",\"regex-syntax/unicode-perl\"],\"unicode-script\":[\"regex-automata/unicode-script\",\"regex-syntax/unicode-script\"],\"unicode-segment\":[\"regex-automata/unicode-segment\",\"regex-syntax/unicode-segment\"],\"unstable\":[\"pattern\"],\"use_std\":[\"std\"]}}", + "ring_0.17.14": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.2.8\"},{\"default_features\":false,\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"getrandom\",\"req\":\"^0.2.10\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(all(any(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), all(target_arch = \\\"arm\\\", target_endian = \\\"little\\\")), any(target_os = \\\"android\\\", target_os = \\\"linux\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_vendor = \\\"apple\\\", any(target_os = \\\"ios\\\", target_os = \\\"macos\\\", target_os = \\\"tvos\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\")))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.37\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\"^0.52\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_os = \\\"windows\\\"))\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\",\"dev_urandom_fallback\"],\"dev_urandom_fallback\":[],\"less-safe-getrandom-custom-or-rdrand\":[],\"less-safe-getrandom-espidf\":[],\"slow_tests\":[],\"std\":[\"alloc\"],\"test_logging\":[],\"unstable-testing-arm-no-hw\":[],\"unstable-testing-arm-no-neon\":[],\"wasm32_unknown_unknown_js\":[\"getrandom/js\"]}}", + "rouille_3.6.2": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.13\"},{\"name\":\"brotli\",\"optional\":true,\"req\":\"^3.3.2\"},{\"default_features\":false,\"features\":[\"clock\"],\"name\":\"chrono\",\"req\":\"^0.4.19\"},{\"features\":[\"gzip\"],\"name\":\"deflate\",\"optional\":true,\"req\":\"^1.0.0\"},{\"name\":\"filetime\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"server\"],\"name\":\"multipart\",\"req\":\"^0.18\"},{\"name\":\"percent-encoding\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"postgres\",\"req\":\"^0.19\"},{\"name\":\"rand\",\"req\":\"^0.8\"},{\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_derive\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"sha1_smol\",\"req\":\"^1.0.0\"},{\"name\":\"threadpool\",\"req\":\"^1\"},{\"features\":[\"local-offset\"],\"name\":\"time\",\"req\":\"^0.3.15\"},{\"default_features\":false,\"name\":\"tiny_http\",\"req\":\"^0.12.0\"},{\"name\":\"url\",\"req\":\"^2\"}],\"features\":{\"default\":[\"gzip\",\"brotli\"],\"gzip\":[\"deflate\"],\"rustls\":[\"tiny_http/ssl-rustls\"],\"ssl\":[\"tiny_http/ssl\"]}}", + "rustc-demangle_0.1.27": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"}],\"features\":{\"compiler_builtins\":[],\"rustc-dep-of-std\":[\"core\"],\"std\":[]}}", + "rustix_1.1.4": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitflags\",\"req\":\"^2.4.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\",\"target\":\"cfg(all(criterion, not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.182\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.182\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.171\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"name\":\"libc_errno\",\"optional\":true,\"package\":\"errno\",\"req\":\"^0.3.10\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc_errno\",\"package\":\"errno\",\"req\":\"^0.3.10\"},{\"default_features\":false,\"features\":[\"general\",\"ioctl\",\"no_std\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.12\",\"target\":\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\"},{\"default_features\":false,\"features\":[\"auxvec\",\"general\",\"errno\",\"ioctl\",\"no_std\",\"elf\"],\"name\":\"linux-raw-sys\",\"req\":\"^0.12\",\"target\":\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\"},{\"kind\":\"dev\",\"name\":\"memoffset\",\"req\":\"^0.9.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.20.3\",\"target\":\"cfg(windows)\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serial_test\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.5.0\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"all-apis\":[\"event\",\"fs\",\"io_uring\",\"mm\",\"mount\",\"net\",\"param\",\"pipe\",\"process\",\"pty\",\"rand\",\"runtime\",\"shm\",\"stdio\",\"system\",\"termios\",\"thread\",\"time\"],\"alloc\":[],\"default\":[\"std\"],\"event\":[],\"fs\":[],\"io_uring\":[\"event\",\"fs\",\"net\",\"thread\",\"linux-raw-sys/io_uring\"],\"linux_4_11\":[],\"linux_5_1\":[\"linux_4_11\"],\"linux_5_11\":[\"linux_5_1\"],\"linux_latest\":[\"linux_5_11\"],\"mm\":[],\"mount\":[],\"net\":[\"linux-raw-sys/net\",\"linux-raw-sys/netlink\",\"linux-raw-sys/if_ether\",\"linux-raw-sys/xdp\"],\"param\":[],\"pipe\":[],\"process\":[\"linux-raw-sys/prctl\"],\"pty\":[\"fs\"],\"rand\":[],\"runtime\":[\"linux-raw-sys/prctl\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\",\"linux-raw-sys/rustc-dep-of-std\",\"bitflags/rustc-dep-of-std\"],\"shm\":[\"fs\"],\"std\":[\"bitflags/std\",\"alloc\",\"libc?/std\",\"libc_errno?/std\"],\"stdio\":[],\"system\":[\"linux-raw-sys/system\"],\"termios\":[],\"thread\":[\"linux-raw-sys/prctl\"],\"time\":[],\"try_close\":[],\"use-explicitly-provided-auxv\":[],\"use-libc\":[\"libc_errno\",\"libc\"],\"use-libc-auxv\":[]}}", + "rustls-pki-types_1.14.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"crabgrind\",\"req\":\"=0.1.9\",\"target\":\"cfg(all(target_os = \\\"linux\\\", target_arch = \\\"x86_64\\\"))\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"dep:zeroize\"],\"default\":[\"alloc\"],\"std\":[\"alloc\"],\"web\":[\"web-time\"]}}", + "rustls-webpki_0.103.13": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.14\"},{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"kind\":\"dev\",\"name\":\"bzip2\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.17.2\"},{\"default_features\":false,\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.12\"},{\"default_features\":false,\"features\":[\"aws_lc_rs\"],\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14.2\"},{\"default_features\":false,\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.18.1\"}],\"features\":{\"alloc\":[\"ring?/alloc\",\"pki-types/alloc\"],\"aws-lc-rs\":[\"dep:aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/prebuilt-nasm\"],\"aws-lc-rs-fips\":[\"dep:aws-lc-rs\",\"aws-lc-rs/fips\"],\"aws-lc-rs-unstable\":[\"aws-lc-rs\",\"aws-lc-rs/unstable\"],\"default\":[\"std\"],\"ring\":[\"dep:ring\"],\"std\":[\"alloc\",\"pki-types/std\"]}}", + "rustls_0.23.40": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aws-lc-rs\",\"optional\":true,\"req\":\"^1.14\"},{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"brotli\",\"optional\":true,\"req\":\"^8\"},{\"name\":\"brotli-decompressor\",\"optional\":true,\"req\":\"^5.0.0\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\",\"inline-more\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.8\"},{\"kind\":\"dev\",\"name\":\"macro_rules_attribute\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4.4\"},{\"default_features\":false,\"features\":[\"alloc\",\"race\"],\"name\":\"once_cell\",\"req\":\"^1.16\"},{\"features\":[\"alloc\"],\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.12\"},{\"default_features\":false,\"features\":[\"pem\",\"aws_lc_rs\"],\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14\"},{\"name\":\"ring\",\"optional\":true,\"req\":\"^0.17\"},{\"kind\":\"build\",\"name\":\"rustversion\",\"optional\":true,\"req\":\"^1.0.6\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.5.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103.5\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17\"},{\"name\":\"zeroize\",\"req\":\"^1.8\"},{\"name\":\"zlib-rs\",\"optional\":true,\"req\":\"^0.6\"}],\"features\":{\"aws-lc-rs\":[\"aws_lc_rs\"],\"aws_lc_rs\":[\"dep:aws-lc-rs\",\"webpki/aws-lc-rs\",\"aws-lc-rs/aws-lc-sys\",\"aws-lc-rs/prebuilt-nasm\"],\"brotli\":[\"dep:brotli\",\"dep:brotli-decompressor\",\"std\"],\"custom-provider\":[],\"default\":[\"aws_lc_rs\",\"logging\",\"prefer-post-quantum\",\"std\",\"tls12\"],\"fips\":[\"aws_lc_rs\",\"aws-lc-rs?/fips\",\"webpki/aws-lc-rs-fips\"],\"logging\":[\"log\"],\"prefer-post-quantum\":[\"aws_lc_rs\"],\"read_buf\":[\"rustversion\",\"std\"],\"ring\":[\"dep:ring\",\"webpki/ring\"],\"std\":[\"webpki/std\",\"pki-types/std\",\"once_cell/std\"],\"tls12\":[],\"zlib\":[\"dep:zlib-rs\"]}}", + "rustversion_1.0.22": "{\"dependencies\":[{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.49\"}],\"features\":{}}", + "ryu_1.0.23": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand_xorshift\",\"req\":\"^0.5\"}],\"features\":{\"small\":[]}}", + "safemem_0.3.3": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "same-file_1.0.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"winapi-util\",\"req\":\"^0.1.1\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "scopeguard_1.2.0": "{\"dependencies\":[],\"features\":{\"default\":[\"use_std\"],\"use_std\":[]}}", + "scroll_0.13.0": "{\"dependencies\":[{\"name\":\"scroll_derive\",\"optional\":true,\"req\":\"^0.13\"}],\"features\":{\"default\":[\"std\"],\"derive\":[\"dep:scroll_derive\"],\"std\":[]}}", + "scroll_derive_0.13.1": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"scroll\",\"req\":\"^0.13\"},{\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", + "semver_1.0.27": "{\"dependencies\":[{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"package\":\"serde_core\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde\"],\"std\":[]}}", + "semver_1.0.28": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"package\":\"serde_core\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"}],\"features\":{\"default\":[\"std\"],\"serde\":[\"dep:serde\"],\"std\":[]}}", + "serde_1.0.228": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"result\"],\"name\":\"serde_core\",\"req\":\"=1.0.228\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"default\":[\"std\"],\"derive\":[\"serde_derive\"],\"rc\":[\"serde_core/rc\"],\"std\":[\"serde_core/std\"],\"unstable\":[\"serde_core/unstable\"]}}", + "serde_core_1.0.228": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_derive\",\"req\":\"=1.0.228\",\"target\":\"cfg(any())\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1\"}],\"features\":{\"alloc\":[],\"default\":[\"std\",\"result\"],\"rc\":[],\"result\":[],\"std\":[],\"unstable\":[]}}", + "serde_derive_1.0.228": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"proc-macro2\",\"req\":\"^1.0.74\"},{\"default_features\":false,\"features\":[\"proc-macro\"],\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"derive\",\"parsing\",\"printing\",\"proc-macro\"],\"name\":\"syn\",\"req\":\"^2.0.81\"}],\"features\":{\"default\":[],\"deserialize_in_place\":[]}}", + "serde_json_1.0.145": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.11\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.3\"},{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2.0.2\"},{\"name\":\"itoa\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"name\":\"ryu\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.194\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.10\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.166\"},{\"kind\":\"dev\",\"name\":\"serde_stacker\",\"req\":\"^0.1.8\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"arbitrary_precision\":[],\"default\":[\"std\"],\"float_roundtrip\":[],\"preserve_order\":[\"indexmap\",\"std\"],\"raw_value\":[],\"std\":[\"memchr/std\",\"serde_core/std\"],\"unbounded_depth\":[]}}", + "serde_json_1.0.149": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1.0.11\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.2.3\"},{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2.0.2\"},{\"name\":\"itoa\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1.0.18\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.13\"},{\"default_features\":false,\"name\":\"serde\",\"req\":\"^1.0.220\",\"target\":\"cfg(any())\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.194\"},{\"kind\":\"dev\",\"name\":\"serde_bytes\",\"req\":\"^0.11.10\"},{\"default_features\":false,\"name\":\"serde_core\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0.166\"},{\"kind\":\"dev\",\"name\":\"serde_stacker\",\"req\":\"^0.1.8\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.108\"},{\"name\":\"zmij\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[\"serde_core/alloc\"],\"arbitrary_precision\":[],\"default\":[\"std\"],\"float_roundtrip\":[],\"preserve_order\":[\"indexmap\",\"std\"],\"raw_value\":[],\"std\":[\"memchr/std\",\"serde_core/std\"],\"unbounded_depth\":[]}}", + "sha1_smol_1.0.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"openssl\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.4\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"std\":[\"alloc\"]}}", + "shlex_1.3.0": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "signal-hook-registry_1.4.8": "{\"dependencies\":[{\"name\":\"errno\",\"req\":\">=0.2, <0.4\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"signal-hook\",\"req\":\"~0.3\"}],\"features\":{}}", + "simd-adler32_0.3.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"adler\",\"req\":\"^1.0.2\"},{\"kind\":\"dev\",\"name\":\"adler32\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"const-generics\":[],\"default\":[\"std\",\"const-generics\"],\"nightly\":[],\"std\":[]}}", + "slab_0.4.12": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.95\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "smallvec_1.15.1": "{\"dependencies\":[{\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"bincode\",\"optional\":true,\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"bincode1\",\"package\":\"bincode\",\"req\":\"^1.0.1\"},{\"kind\":\"dev\",\"name\":\"debugger_test\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"debugger_test_parser\",\"req\":\"^0.1.0\"},{\"default_features\":false,\"name\":\"malloc_size_of\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"unty\",\"optional\":true,\"req\":\"^0.0.4\"}],\"features\":{\"const_generics\":[],\"const_new\":[\"const_generics\"],\"debugger_visualizer\":[],\"drain_filter\":[],\"drain_keep_rest\":[\"drain_filter\"],\"impl_bincode\":[\"bincode\",\"unty\"],\"may_dangle\":[],\"specialization\":[],\"union\":[],\"write\":[]}}", + "socket2_0.6.3": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.172\",\"target\":\"cfg(any(unix, target_os = \\\"wasi\\\"))\"},{\"features\":[\"Win32_Foundation\",\"Win32_Networking_WinSock\",\"Win32_System_IO\",\"Win32_System_Threading\",\"Win32_System_WindowsProgramming\"],\"name\":\"windows-sys\",\"req\":\">=0.60, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"all\":[]}}", + "stable_deref_trait_1.2.1": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", + "strsim_0.11.1": "{\"dependencies\":[],\"features\":{}}", + "subtle_2.6.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"const-generics\":[],\"core_hint_black_box\":[],\"default\":[\"std\",\"i128\"],\"i128\":[],\"nightly\":[],\"std\":[]}}", + "syn_2.0.117": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"automod\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.91\"},{\"default_features\":false,\"name\":\"quote\",\"optional\":true,\"req\":\"^1.0.35\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"ref-cast\",\"req\":\"^1\"},{\"features\":[\"blocking\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.13\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"syn-test-suite\",\"req\":\"^0\"},{\"kind\":\"dev\",\"name\":\"tar\",\"req\":\"^0.4.16\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"termcolor\",\"req\":\"^1\"},{\"name\":\"unicode-ident\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\",\"target\":\"cfg(not(miri))\"}],\"features\":{\"clone-impls\":[],\"default\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"proc-macro\"],\"derive\":[],\"extra-traits\":[],\"fold\":[],\"full\":[],\"parsing\":[],\"printing\":[\"dep:quote\"],\"proc-macro\":[\"proc-macro2/proc-macro\",\"quote?/proc-macro\"],\"test\":[\"syn-test-suite/all-features\"],\"visit\":[],\"visit-mut\":[]}}", + "sync_wrapper_1.0.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"}],\"features\":{\"futures\":[\"futures-core\"]}}", + "synstructure_0.13.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"visit\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"synstructure_test_traits\",\"req\":\"^0.1\"}],\"features\":{\"default\":[\"proc-macro\"],\"proc-macro\":[\"proc-macro2/proc-macro\",\"syn/proc-macro\",\"quote/proc-macro\"]}}", + "target-lexicon_0.13.5": "{\"dependencies\":[{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"arch_z80\":[],\"arch_zkasm\":[],\"default\":[],\"serde_support\":[\"serde\",\"std\"],\"std\":[]}}", + "tempfile_3.27.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"fastrand\",\"req\":\"^2.1.1\"},{\"default_features\":false,\"name\":\"getrandom\",\"optional\":true,\"req\":\">=0.3.0, <0.5\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"once_cell\",\"req\":\"^1.19.0\"},{\"features\":[\"fs\"],\"name\":\"rustix\",\"req\":\"^1.1.4\",\"target\":\"cfg(any(unix, target_os = \\\"wasi\\\"))\"},{\"features\":[\"Win32_Storage_FileSystem\",\"Win32_Foundation\"],\"name\":\"windows-sys\",\"req\":\">=0.52, <0.62\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"getrandom\"],\"nightly\":[]}}", + "threadpool_1.8.1": "{\"dependencies\":[{\"name\":\"num_cpus\",\"req\":\"^1.13\"}],\"features\":{}}", + "time-core_0.1.8": "{\"dependencies\":[],\"features\":{\"large-dates\":[]}}", + "time_0.3.47": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.1\",\"target\":\"cfg(bench)\"},{\"features\":[\"powerfmt\"],\"name\":\"deranged\",\"req\":\"^0.5.2\"},{\"name\":\"itoa\",\"optional\":true,\"req\":\"^1.0.1\"},{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3.58\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(any(target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.98\",\"target\":\"cfg(target_family = \\\"unix\\\")\"},{\"name\":\"num-conv\",\"req\":\"^0.2.0\"},{\"kind\":\"dev\",\"name\":\"num-conv\",\"req\":\"^0.2.0\"},{\"name\":\"num_threads\",\"optional\":true,\"req\":\"^0.1.2\",\"target\":\"cfg(target_family = \\\"unix\\\")\"},{\"default_features\":false,\"name\":\"powerfmt\",\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"rand08\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rand08\",\"package\":\"rand\",\"req\":\"^0.8.4\"},{\"default_features\":false,\"name\":\"rand09\",\"optional\":true,\"package\":\"rand\",\"req\":\"^0.9.2\"},{\"default_features\":false,\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand09\",\"package\":\"rand\",\"req\":\"^0.9.2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26.1\"},{\"kind\":\"dev\",\"name\":\"rstest_reuse\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.184\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.68\"},{\"kind\":\"dev\",\"name\":\"serde_test\",\"req\":\"^1.0.126\"},{\"name\":\"time-core\",\"req\":\"=0.1.8\"},{\"name\":\"time-macros\",\"optional\":true,\"req\":\"=0.2.27\"},{\"kind\":\"dev\",\"name\":\"time-macros\",\"req\":\"=0.2.27\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.102\",\"target\":\"cfg(__ui_tests)\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\"],\"default\":[\"std\"],\"formatting\":[\"dep:itoa\",\"std\",\"time-macros?/formatting\"],\"large-dates\":[\"time-core/large-dates\",\"time-macros?/large-dates\"],\"local-offset\":[\"std\",\"dep:libc\",\"dep:num_threads\"],\"macros\":[\"dep:time-macros\"],\"parsing\":[\"time-macros?/parsing\"],\"quickcheck\":[\"dep:quickcheck\",\"alloc\",\"deranged/quickcheck\"],\"rand\":[\"rand08\",\"rand09\"],\"rand08\":[\"dep:rand08\",\"deranged/rand08\"],\"rand09\":[\"dep:rand09\",\"deranged/rand09\"],\"serde\":[\"dep:serde_core\",\"time-macros?/serde\",\"deranged/serde\"],\"serde-human-readable\":[\"serde\",\"formatting\",\"parsing\"],\"serde-well-known\":[\"serde\",\"formatting\",\"parsing\"],\"std\":[\"alloc\"],\"wasm-bindgen\":[\"dep:js-sys\"]}}", + "tiny_http_0.12.0": "{\"dependencies\":[{\"name\":\"ascii\",\"req\":\"^1.0\"},{\"name\":\"chunked_transfer\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"fdlimit\",\"req\":\"^0.1\"},{\"name\":\"httpdate\",\"req\":\"^1.0.2\"},{\"name\":\"log\",\"req\":\"^0.4.4\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"rustc-serialize\",\"req\":\"^0.3\"},{\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.20\"},{\"name\":\"rustls-pemfile\",\"optional\":true,\"req\":\"^0.2.1\"},{\"kind\":\"dev\",\"name\":\"sha1\",\"req\":\"^0.6.0\"},{\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"default\":[],\"ssl\":[\"ssl-openssl\"],\"ssl-openssl\":[\"openssl\",\"zeroize\"],\"ssl-rustls\":[\"rustls\",\"rustls-pemfile\",\"zeroize\"]}}", + "tinystr_0.8.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2.3\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"name\":\"zerovec\",\"optional\":true,\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"serde_core?/alloc\",\"zerovec?/alloc\"],\"databake\":[\"dep:databake\"],\"default\":[\"alloc\"],\"serde\":[\"dep:serde_core\"],\"std\":[],\"zerovec\":[\"dep:zerovec\"]}}", + "tokio-macros_2.6.1": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"features\":[\"full\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0.0\"}],\"features\":{}}", + "tokio-stream_0.1.18": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"futures-core\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"^0.12.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"req\":\"^1.15.0\"},{\"features\":[\"full\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.2.0\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4\"},{\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7.0\"}],\"features\":{\"default\":[\"time\"],\"fs\":[\"tokio/fs\"],\"full\":[\"time\",\"net\",\"io-util\",\"fs\",\"sync\",\"signal\"],\"io-util\":[\"tokio/io-util\"],\"net\":[\"tokio/net\"],\"signal\":[\"tokio/signal\"],\"sync\":[\"tokio/sync\",\"tokio-util\"],\"time\":[\"tokio/time\"]}}", + "tokio-util_0.7.17": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3.0\"},{\"name\":\"bytes\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.0\"},{\"name\":\"futures-core\",\"req\":\"^0.3.0\"},{\"name\":\"futures-io\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"futures-sink\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"futures-test\",\"req\":\"^0.3.5\"},{\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.0\"},{\"default_features\":false,\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15.0\"},{\"kind\":\"dev\",\"name\":\"parking_lot\",\"req\":\"^0.12.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.4\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"},{\"features\":[\"sync\"],\"name\":\"tokio\",\"req\":\"^1.28.0\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.29\"}],\"features\":{\"__docs_rs\":[\"futures-util\"],\"codec\":[],\"compat\":[\"futures-io\"],\"default\":[],\"full\":[\"codec\",\"compat\",\"io-util\",\"time\",\"net\",\"rt\",\"join-map\"],\"io\":[],\"io-util\":[\"io\",\"tokio/rt\",\"tokio/io-util\"],\"join-map\":[\"rt\",\"hashbrown\"],\"net\":[\"tokio/net\"],\"rt\":[\"tokio/rt\",\"tokio/sync\",\"futures-util\"],\"time\":[\"tokio/time\",\"slab\"]}}", + "tokio_1.50.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3\"},{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.58\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.2.1\"},{\"features\":[\"async-await\"],\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"futures-concurrency\",\"req\":\"^7.6.3\"},{\"kind\":\"dev\",\"name\":\"futures-test\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"name\":\"io-uring\",\"optional\":true,\"req\":\"^0.7.11\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.168\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.168\",\"target\":\"cfg(unix)\"},{\"features\":[\"futures\",\"checkpoint\"],\"kind\":\"dev\",\"name\":\"loom\",\"req\":\"^0.7\",\"target\":\"cfg(loom)\"},{\"default_features\":false,\"name\":\"mio\",\"optional\":true,\"req\":\"^1.0.1\"},{\"default_features\":false,\"features\":[\"os-poll\",\"os-ext\"],\"name\":\"mio\",\"optional\":true,\"req\":\"^1.0.1\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"features\":[\"tokio\"],\"kind\":\"dev\",\"name\":\"mio-aio\",\"req\":\"^1\",\"target\":\"cfg(target_os = \\\"freebsd\\\")\"},{\"kind\":\"dev\",\"name\":\"mockall\",\"req\":\"^0.13.0\"},{\"default_features\":false,\"features\":[\"aio\",\"fs\",\"socket\"],\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.29.0\",\"target\":\"cfg(unix)\"},{\"name\":\"parking_lot\",\"optional\":true,\"req\":\"^0.12.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"signal-hook-registry\",\"optional\":true,\"req\":\"^1.1.1\",\"target\":\"cfg(unix)\"},{\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.9\",\"target\":\"cfg(all(tokio_unstable, target_os = \\\"linux\\\"))\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"socket2\",\"req\":\"^0.6.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"name\":\"tokio-macros\",\"optional\":true,\"req\":\"~2.6.0\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.0\"},{\"features\":[\"rt\"],\"kind\":\"dev\",\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.29\",\"target\":\"cfg(tokio_unstable)\"},{\"kind\":\"dev\",\"name\":\"tracing-mock\",\"req\":\"=0.1.0-beta.1\",\"target\":\"cfg(all(tokio_unstable, target_has_atomic = \\\"64\\\"))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.0\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"windows-sys\",\"optional\":true,\"req\":\"^0.61\",\"target\":\"cfg(windows)\"},{\"features\":[\"Win32_Foundation\",\"Win32_Security_Authorization\"],\"kind\":\"dev\",\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[],\"fs\":[],\"full\":[\"fs\",\"io-util\",\"io-std\",\"macros\",\"net\",\"parking_lot\",\"process\",\"rt\",\"rt-multi-thread\",\"signal\",\"sync\",\"time\"],\"io-std\":[],\"io-uring\":[\"dep:io-uring\",\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"dep:slab\"],\"io-util\":[\"bytes\"],\"macros\":[\"tokio-macros\"],\"net\":[\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"mio/net\",\"socket2\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_Security\",\"windows-sys/Win32_Storage_FileSystem\",\"windows-sys/Win32_System_Pipes\",\"windows-sys/Win32_System_SystemServices\"],\"process\":[\"bytes\",\"libc\",\"mio/os-poll\",\"mio/os-ext\",\"mio/net\",\"signal-hook-registry\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_System_Threading\",\"windows-sys/Win32_System_WindowsProgramming\"],\"rt\":[],\"rt-multi-thread\":[\"rt\"],\"signal\":[\"libc\",\"mio/os-poll\",\"mio/net\",\"mio/os-ext\",\"signal-hook-registry\",\"windows-sys/Win32_Foundation\",\"windows-sys/Win32_System_Console\"],\"sync\":[],\"taskdump\":[\"dep:backtrace\"],\"test-util\":[\"rt\",\"sync\",\"time\"],\"time\":[]}}", + "tonic-build_0.14.5": "{\"dependencies\":[{\"name\":\"prettyplease\",\"req\":\"^0.2\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{\"default\":[\"transport\"],\"transport\":[]}}", + "tonic-prost_0.14.5": "{\"dependencies\":[{\"name\":\"bytes\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"http-body\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"name\":\"prost\",\"req\":\"^0.14\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"tonic\",\"req\":\"^0.14.0\"}],\"features\":{}}", + "tonic_0.14.5": "{\"dependencies\":[{\"name\":\"async-trait\",\"optional\":true,\"req\":\"^0.1.13\"},{\"default_features\":false,\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1.5\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"http\",\"req\":\"^1.1.0\"},{\"name\":\"http-body\",\"req\":\"^1\"},{\"name\":\"http-body-util\",\"req\":\"^0.1\"},{\"features\":[\"http1\",\"http2\"],\"name\":\"hyper\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"hyper-timeout\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"tokio\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.11\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project\",\"req\":\"^1.0.11\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8\"},{\"features\":[\"all\"],\"name\":\"socket2\",\"optional\":true,\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.0\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.2\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"logging\",\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26.1\"},{\"default_features\":false,\"name\":\"tokio-stream\",\"req\":\"^0.1.16\"},{\"default_features\":false,\"name\":\"tower\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"load-shed\",\"timeout\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5\"},{\"name\":\"tower-layer\",\"req\":\"^0.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"zstd\",\"optional\":true,\"req\":\"^0.13.0\"}],\"features\":{\"_tls-any\":[\"dep:tokio\",\"tokio?/rt\",\"tokio?/macros\",\"tls-connect-info\"],\"channel\":[\"dep:hyper\",\"hyper?/client\",\"dep:hyper-util\",\"hyper-util?/client-legacy\",\"dep:tower\",\"tower?/balance\",\"tower?/buffer\",\"tower?/discover\",\"tower?/limit\",\"tower?/load-shed\",\"tower?/util\",\"dep:tokio\",\"tokio?/time\",\"dep:hyper-timeout\"],\"codegen\":[\"dep:async-trait\"],\"default\":[\"router\",\"transport\",\"codegen\"],\"deflate\":[\"dep:flate2\"],\"gzip\":[\"dep:flate2\"],\"router\":[\"dep:axum\",\"dep:tower\",\"tower?/util\"],\"server\":[\"dep:h2\",\"dep:hyper\",\"hyper?/server\",\"dep:hyper-util\",\"hyper-util?/service\",\"hyper-util?/server-auto\",\"dep:socket2\",\"dep:tokio\",\"tokio?/macros\",\"tokio?/net\",\"tokio?/time\",\"tokio-stream/net\",\"dep:tower\",\"tower?/util\",\"tower?/limit\",\"tower?/load-shed\"],\"tls-aws-lc\":[\"_tls-any\",\"tokio-rustls/aws-lc-rs\"],\"tls-connect-info\":[\"dep:tokio-rustls\"],\"tls-native-roots\":[\"_tls-any\",\"channel\",\"dep:rustls-native-certs\"],\"tls-ring\":[\"_tls-any\",\"tokio-rustls/ring\"],\"tls-webpki-roots\":[\"_tls-any\",\"channel\",\"dep:webpki-roots\"],\"transport\":[\"server\",\"channel\"],\"zstd\":[\"dep:zstd\"]}}", + "tower-layer_0.3.3": "{\"dependencies\":[],\"features\":{}}", + "tower-service_0.3.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.22\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^0.2\"},{\"features\":[\"macros\",\"time\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.6.2\"},{\"kind\":\"dev\",\"name\":\"tower-layer\",\"req\":\"^0.3\"}],\"features\":{}}", + "tower_0.5.3": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.22\"},{\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.22\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.22\"},{\"default_features\":false,\"features\":[\"async-await-macro\"],\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.22\"},{\"default_features\":false,\"name\":\"hdrhistogram\",\"optional\":true,\"req\":\"^7.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"hdrhistogram\",\"req\":\"^7.0\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^1\"},{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.0.2\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"name\":\"slab\",\"optional\":true,\"req\":\"^0.4.9\"},{\"name\":\"sync_wrapper\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"tokio\",\"optional\":true,\"req\":\"^1.6.2\"},{\"features\":[\"macros\",\"sync\",\"test-util\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.6.2\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1.1\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.3\"},{\"name\":\"tower-service\",\"req\":\"^0.3.3\"},{\"kind\":\"dev\",\"name\":\"tower-test\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1.2\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.2\"},{\"default_features\":false,\"features\":[\"fmt\",\"ansi\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"}],\"features\":{\"balance\":[\"discover\",\"load\",\"ready-cache\",\"make\",\"slab\",\"util\"],\"buffer\":[\"tokio/sync\",\"tokio/rt\",\"tokio-util\",\"tracing\",\"pin-project-lite\"],\"discover\":[\"futures-core\",\"pin-project-lite\"],\"filter\":[\"futures-util\",\"pin-project-lite\"],\"full\":[\"balance\",\"buffer\",\"discover\",\"filter\",\"hedge\",\"limit\",\"load\",\"load-shed\",\"make\",\"ready-cache\",\"reconnect\",\"retry\",\"spawn-ready\",\"steer\",\"timeout\",\"util\"],\"hedge\":[\"util\",\"filter\",\"futures-util\",\"hdrhistogram\",\"tokio/time\",\"tracing\"],\"limit\":[\"tokio/time\",\"tokio/sync\",\"tokio-util\",\"tracing\",\"pin-project-lite\"],\"load\":[\"tokio/time\",\"tracing\",\"pin-project-lite\"],\"load-shed\":[\"pin-project-lite\"],\"log\":[\"tracing/log\"],\"make\":[\"pin-project-lite\",\"tokio\"],\"ready-cache\":[\"futures-core\",\"futures-util\",\"indexmap\",\"tokio/sync\",\"tracing\",\"pin-project-lite\"],\"reconnect\":[\"make\",\"tracing\"],\"retry\":[\"tokio/time\",\"util\"],\"spawn-ready\":[\"futures-util\",\"tokio/sync\",\"tokio/rt\",\"util\",\"tracing\"],\"steer\":[],\"timeout\":[\"pin-project-lite\",\"tokio/time\"],\"tokio-stream\":[],\"util\":[\"futures-core\",\"futures-util\",\"pin-project-lite\",\"sync_wrapper\"]}}", + "tracing-attributes_0.1.31": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1.67\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"name\":\"quote\",\"req\":\"^1.0.20\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0.9\"},{\"default_features\":false,\"features\":[\"full\",\"parsing\",\"printing\",\"visit-mut\",\"clone-impls\",\"extra-traits\",\"proc-macro\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"tokio-test\",\"req\":\"^0.4.2\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"features\":[\"env-filter\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.64\"}],\"features\":{\"async-await\":[]}}", + "tracing-core_0.1.36": "{\"dependencies\":[{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.13.0\"},{\"default_features\":false,\"name\":\"valuable\",\"optional\":true,\"req\":\"^0.1.0\",\"target\":\"cfg(tracing_unstable)\"}],\"features\":{\"default\":[\"std\",\"valuable?/std\"],\"std\":[\"once_cell\"]}}", + "tracing_0.1.44": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.21\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.9\"},{\"name\":\"tracing-attributes\",\"optional\":true,\"req\":\"^0.1.31\"},{\"default_features\":false,\"name\":\"tracing-core\",\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.38\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"}],\"features\":{\"async-await\":[],\"attributes\":[\"tracing-attributes\"],\"default\":[\"std\",\"attributes\"],\"log-always\":[\"log\"],\"max_level_debug\":[],\"max_level_error\":[],\"max_level_info\":[],\"max_level_off\":[],\"max_level_trace\":[],\"max_level_warn\":[],\"release_max_level_debug\":[],\"release_max_level_error\":[],\"release_max_level_info\":[],\"release_max_level_off\":[],\"release_max_level_trace\":[],\"release_max_level_warn\":[],\"std\":[\"tracing-core/std\"],\"valuable\":[\"tracing-core/valuable\"]}}", + "try-lock_0.2.5": "{\"dependencies\":[],\"features\":{}}", + "twoway_0.1.8": "{\"dependencies\":[{\"name\":\"galil-seiferas\",\"optional\":true,\"req\":\"^0.1.1\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.7.0\"},{\"features\":[\"unstable\"],\"name\":\"jetscii\",\"optional\":true,\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"macro-attr\",\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"memchr\",\"req\":\"^2.0\"},{\"kind\":\"dev\",\"name\":\"newtype_derive\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"odds\",\"req\":\"^0.2.26\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.3.10\"},{\"name\":\"unchecked-index\",\"optional\":true,\"req\":\"^0.2.2\"}],\"features\":{\"all\":[\"jetscii\",\"pcmp\",\"pattern\",\"test-set\"],\"benchmarks\":[\"galil-seiferas\",\"pattern\",\"unchecked-index\"],\"default\":[\"use_std\"],\"pattern\":[],\"pcmp\":[\"unchecked-index\"],\"test-set\":[],\"use_std\":[\"memchr/use_std\"]}}", + "unicase_2.9.0": "{\"dependencies\":[],\"features\":{\"nightly\":[]}}", + "unicode-ident_1.0.24": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"kind\":\"dev\",\"name\":\"fst\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"roaring\",\"req\":\"^0.11\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"ucd-trie\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"unicode-xid\",\"req\":\"^0.2.6\"}],\"features\":{}}", + "unicode-xid_0.2.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"}],\"features\":{\"bench\":[],\"default\":[],\"no_std\":[]}}", + "untrusted_0.9.0": "{\"dependencies\":[],\"features\":{}}", + "ureq_2.12.1": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"brotli-decompressor\",\"optional\":true,\"req\":\"^4.0.0\"},{\"default_features\":false,\"name\":\"cookie\",\"optional\":true,\"req\":\"^0.18\"},{\"default_features\":false,\"features\":[\"preserve_order\",\"serde_json\"],\"name\":\"cookie_store\",\"optional\":true,\"req\":\"^0.21.1\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"features\":[\"humantime\"],\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"<=0.9\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0.22\"},{\"name\":\"hootbin\",\"optional\":true,\"req\":\"^0.1.5\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"name\":\"http-02\",\"optional\":true,\"package\":\"http\",\"req\":\"^0.2\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"name\":\"native-tls\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"once_cell\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"ring\",\"logging\",\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.19\"},{\"default_features\":false,\"features\":[\"std\",\"ring\"],\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23.5\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"rustls-pemfile\",\"req\":\"^2.0\"},{\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.97\"},{\"name\":\"socks\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"url\",\"req\":\"^2.5.0\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^0.26\"}],\"features\":{\"brotli\":[\"dep:brotli-decompressor\"],\"charset\":[\"dep:encoding_rs\"],\"cookies\":[\"dep:cookie\",\"dep:cookie_store\"],\"default\":[\"tls\",\"gzip\"],\"gzip\":[\"dep:flate2\"],\"http-crate\":[\"dep:http\"],\"http-interop\":[\"dep:http-02\"],\"json\":[\"dep:serde\",\"dep:serde_json\"],\"native-certs\":[\"dep:rustls-native-certs\"],\"native-tls\":[\"dep:native-tls\"],\"proxy-from-env\":[],\"socks-proxy\":[\"dep:socks\"],\"testdeps\":[\"dep:hootbin\"],\"tls\":[\"dep:webpki-roots\",\"dep:rustls\",\"dep:rustls-pki-types\"]}}", + "url_2.5.8": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bencher\",\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"form_urlencoded\",\"req\":\"^1.2.2\"},{\"default_features\":false,\"features\":[\"alloc\",\"compiled_data\"],\"name\":\"idna\",\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"percent-encoding\",\"req\":\"^2.3.2\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"}],\"features\":{\"debugger_visualizer\":[],\"default\":[\"std\"],\"expose_internals\":[],\"serde\":[\"dep:serde\",\"dep:serde_derive\"],\"std\":[\"idna/std\",\"percent-encoding/std\",\"form_urlencoded/std\",\"serde?/std\"]}}", + "utf8_iter_1.0.4": "{\"dependencies\":[],\"features\":{}}", + "utf8parse_0.2.2": "{\"dependencies\":[],\"features\":{\"default\":[],\"nightly\":[]}}", + "version_check_0.9.5": "{\"dependencies\":[],\"features\":{}}", + "walkdir_2.5.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"same-file\",\"req\":\"^1.0.1\"},{\"name\":\"winapi-util\",\"req\":\"^0.1.1\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "walrus-macro_0.24.0": "{\"dependencies\":[{\"name\":\"heck\",\"req\":\"^0.5.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.86\"},{\"name\":\"quote\",\"req\":\"^1.0.37\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.77\"}],\"features\":{}}", + "walrus_0.24.5": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11.0\"},{\"name\":\"gimli\",\"req\":\"^0.26.0\"},{\"name\":\"id-arena\",\"req\":\"^2.2.1\"},{\"name\":\"leb128\",\"req\":\"^0.2.4\"},{\"name\":\"log\",\"req\":\"^0.4.8\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.1.0\"},{\"name\":\"walrus-macro\",\"req\":\"=0.24.0\"},{\"name\":\"wasm-encoder\",\"req\":\"^0.240.0\"},{\"name\":\"wasmparser\",\"req\":\"^0.240.0\"}],\"features\":{\"parallel\":[\"rayon\",\"id-arena/rayon\"]}}", + "want_0.3.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"tokio-executor\",\"req\":\"^0.2.0-alpha.2\"},{\"kind\":\"dev\",\"name\":\"tokio-sync\",\"req\":\"^0.2.0-alpha.2\"},{\"name\":\"try-lock\",\"req\":\"^0.2.4\"}],\"features\":{}}", + "wasi_0.11.1+wasi-snapshot-preview1": "{\"dependencies\":[{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"rustc-std-workspace-alloc\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"default\":[\"std\"],\"rustc-dep-of-std\":[\"core\",\"rustc-std-workspace-alloc\"],\"std\":[]}}", + "wasip2_1.0.2+wasi-0.2.9": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"wit-bindgen\",\"req\":\"^0.51.0\"}],\"features\":{\"bitflags\":[\"wit-bindgen/bitflags\"],\"default\":[\"std\",\"bitflags\"],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"wit-bindgen/rustc-dep-of-std\"],\"std\":[]}}", + "wasip2_1.0.3+wasi-0.2.9": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"wit-bindgen\",\"req\":\"^0.57.1\"}],\"features\":{\"bitflags\":[\"wit-bindgen/bitflags\"],\"default\":[\"std\",\"bitflags\"],\"rustc-dep-of-std\":[\"core\",\"alloc\",\"wit-bindgen/rustc-dep-of-std\"],\"std\":[]}}", + "wasip3_0.4.0+wasi-0.3.0-rc-2026-01-06": "{\"dependencies\":[{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1.10.1\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.31\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"http\",\"req\":\"^1.3.1\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1.0.1\"},{\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2.0.17\"},{\"default_features\":false,\"features\":[\"async\"],\"name\":\"wit-bindgen\",\"req\":\"^0.51.0\"},{\"default_features\":false,\"features\":[\"async-spawn\"],\"kind\":\"dev\",\"name\":\"wit-bindgen\",\"req\":\"^0.51.0\"}],\"features\":{\"http-compat\":[\"dep:bytes\",\"dep:http-body\",\"dep:http\",\"dep:thiserror\",\"wit-bindgen/async-spawn\"]}}", + "wasm-bindgen-cli-support_0.2.105": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"base64\",\"req\":\"^0.22\"},{\"name\":\"leb128\",\"req\":\"^0.2\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"name\":\"rustc-demangle\",\"req\":\"^0.1.13\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"parallel\"],\"name\":\"walrus\",\"req\":\"^0.24.2\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.105\"},{\"name\":\"wasmparser\",\"req\":\"^0.214\"},{\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.214\"},{\"kind\":\"dev\",\"name\":\"wast\",\"req\":\"^214\"},{\"kind\":\"dev\",\"name\":\"wat\",\"req\":\"^1.0\"}],\"features\":{}}", + "wasm-bindgen-cli_0.2.105": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"assert_cmd\",\"req\":\"^2\"},{\"features\":[\"derive\"],\"name\":\"clap\",\"req\":\"^4\"},{\"name\":\"env_logger\",\"req\":\"^0.11.5\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"native-tls\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"predicates\",\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.4\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.11.2\"},{\"default_features\":false,\"name\":\"rouille\",\"req\":\"^3.0.0\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"shlex\",\"req\":\"^1\"},{\"name\":\"tempfile\",\"req\":\"^3.0\"},{\"default_features\":false,\"features\":[\"brotli\",\"gzip\"],\"name\":\"ureq\",\"req\":\"^2.7\"},{\"name\":\"walrus\",\"req\":\"^0.24.2\"},{\"name\":\"wasm-bindgen-cli-support\",\"req\":\"=0.2.105\"},{\"kind\":\"dev\",\"name\":\"wasmparser\",\"req\":\"^0.214\"},{\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.214\"}],\"features\":{\"default\":[\"rustls-tls\"],\"native-tls\":[\"ureq/native-tls\"],\"openssl\":[\"dep:native-tls\"],\"rustls-tls\":[\"ureq/tls\"],\"vendored-openssl\":[\"openssl\",\"native-tls/vendored\"]}}", + "wasm-bindgen-futures_0.4.55": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"futures-channel\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3.8\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.82\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"},{\"default_features\":false,\"features\":[\"MessageEvent\",\"Worker\"],\"name\":\"web-sys\",\"req\":\"=0.3.82\",\"target\":\"cfg(target_feature = \\\"atomics\\\")\"}],\"features\":{\"default\":[\"std\"],\"futures-core-03-stream\":[\"futures-core\"],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\",\"web-sys/std\"]}}", + "wasm-bindgen-macro-support_0.2.105": "{\"dependencies\":[{\"name\":\"bumpalo\",\"req\":\"^3.0.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"features\":[\"visit\",\"visit-mut\",\"full\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.105\"}],\"features\":{\"extra-traits\":[\"syn/extra-traits\"],\"strict-macro\":[]}}", + "wasm-bindgen-macro_0.2.105": "{\"dependencies\":[{\"name\":\"quote\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro-support\",\"req\":\"=0.2.105\"}],\"features\":{\"strict-macro\":[\"wasm-bindgen-macro-support/strict-macro\"]}}", + "wasm-bindgen-shared_0.2.105": "{\"dependencies\":[{\"name\":\"unicode-ident\",\"req\":\"^1.0.5\"}],\"features\":{}}", + "wasm-bindgen-test-macro_0.3.55": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"parsing\",\"proc-macro\",\"derive\",\"printing\"],\"name\":\"syn\",\"req\":\"^2.0\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0\"}],\"features\":{}}", + "wasm-bindgen-test_0.3.55": "{\"dependencies\":[{\"name\":\"gg-alloc\",\"optional\":true,\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.82\"},{\"name\":\"minicov\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", wasm_bindgen_unstable_test_coverage))\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"},{\"default_features\":false,\"name\":\"wasm-bindgen-futures\",\"req\":\"=0.4.55\"},{\"name\":\"wasm-bindgen-test-macro\",\"req\":\"=0.3.55\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\",\"wasm-bindgen-futures/std\"]}}", + "wasm-bindgen_0.2.105": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"name\":\"once_cell\",\"req\":\"^1.12\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"build\",\"name\":\"rustversion-compat\",\"package\":\"rustversion\",\"req\":\"^1.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"wasm-bindgen-macro\",\"req\":\"=0.2.105\"},{\"name\":\"wasm-bindgen-shared\",\"req\":\"=0.2.105\"}],\"features\":{\"default\":[\"std\"],\"enable-interning\":[\"std\"],\"gg-alloc\":[],\"msrv\":[],\"rustversion\":[],\"serde-serialize\":[\"serde\",\"serde_json\",\"std\"],\"spans\":[],\"std\":[],\"strict-macro\":[\"wasm-bindgen-macro/strict-macro\"],\"xxx_debug_only_print_generated_code\":[]}}", + "wasm-encoder_0.240.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"default_features\":false,\"name\":\"leb128fmt\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.2.0\"},{\"default_features\":false,\"features\":[\"simd\",\"simd\"],\"name\":\"wasmparser\",\"optional\":true,\"req\":\"^0.240.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.240.0\"}],\"features\":{\"component-model\":[\"wasmparser?/component-model\"],\"default\":[\"std\",\"component-model\"],\"std\":[\"wasmparser?/std\"]}}", + "wasm-encoder_0.244.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"default_features\":false,\"name\":\"leb128fmt\",\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.2.0\"},{\"default_features\":false,\"features\":[\"simd\",\"simd\"],\"name\":\"wasmparser\",\"optional\":true,\"req\":\"^0.244.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.244.0\"}],\"features\":{\"component-model\":[\"wasmparser?/component-model\"],\"default\":[\"std\",\"component-model\"],\"std\":[\"wasmparser?/std\"]}}", + "wasm-metadata_0.244.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"auditable-serde\",\"optional\":true,\"req\":\"^0.8.0\"},{\"features\":[\"derive\"],\"name\":\"clap\",\"optional\":true,\"req\":\"^4.0.0\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"serde\"],\"name\":\"indexmap\",\"req\":\"^2.7.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0.166\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"spdx\",\"optional\":true,\"req\":\"^0.10.1\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"features\":[\"std\",\"component-model\"],\"name\":\"wasm-encoder\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"simd\",\"std\",\"component-model\",\"hash-collections\"],\"name\":\"wasmparser\",\"req\":\"^0.244.0\"}],\"features\":{\"default\":[\"oci\",\"serde\"],\"oci\":[\"dep:auditable-serde\",\"dep:flate2\",\"dep:url\",\"dep:spdx\",\"dep:serde_json\",\"serde\"],\"serde\":[\"dep:serde_derive\",\"dep:serde\"]}}", + "wasmparser_0.214.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ahash\",\"optional\":true,\"req\":\"^0.8.11\"},{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.4.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"ahash\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.14.3\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"semver\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"}],\"features\":{\"default\":[\"std\",\"validate\",\"serde\"],\"no-hash-maps\":[],\"serde\":[\"dep:serde\",\"indexmap/serde\",\"hashbrown/serde\"],\"std\":[\"indexmap/std\"],\"validate\":[\"dep:indexmap\",\"dep:semver\",\"dep:hashbrown\",\"dep:ahash\"]}}", + "wasmparser_0.240.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.4.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.7.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"semver\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"}],\"features\":{\"component-model\":[\"dep:semver\"],\"default\":[\"std\",\"validate\",\"serde\",\"features\",\"component-model\",\"hash-collections\",\"simd\"],\"features\":[],\"hash-collections\":[\"dep:hashbrown\",\"dep:indexmap\"],\"prefer-btree-collections\":[],\"serde\":[\"dep:serde\",\"indexmap?/serde\",\"hashbrown?/serde\"],\"simd\":[],\"std\":[\"indexmap?/std\"],\"validate\":[]}}", + "wasmparser_0.244.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.4.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.1\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"default-hasher\"],\"name\":\"hashbrown\",\"optional\":true,\"req\":\"^0.15.2\"},{\"default_features\":false,\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.7.0\"},{\"kind\":\"dev\",\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1.13.0\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.3\"},{\"default_features\":false,\"name\":\"semver\",\"optional\":true,\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"}],\"features\":{\"component-model\":[\"dep:semver\"],\"default\":[\"std\",\"validate\",\"serde\",\"features\",\"component-model\",\"hash-collections\",\"simd\"],\"features\":[],\"hash-collections\":[\"dep:hashbrown\",\"dep:indexmap\"],\"prefer-btree-collections\":[],\"serde\":[\"dep:serde\",\"indexmap?/serde\",\"hashbrown?/serde\"],\"simd\":[],\"std\":[\"indexmap?/std\"],\"validate\":[]}}", + "web-sys_0.3.82": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"default_features\":false,\"name\":\"js-sys\",\"req\":\"=0.3.82\"},{\"default_features\":false,\"name\":\"wasm-bindgen\",\"req\":\"=0.2.105\"}],\"features\":{\"AbortController\":[],\"AbortSignal\":[\"EventTarget\"],\"AddEventListenerOptions\":[],\"AesCbcParams\":[],\"AesCtrParams\":[],\"AesDerivedKeyParams\":[],\"AesGcmParams\":[],\"AesKeyAlgorithm\":[],\"AesKeyGenParams\":[],\"Algorithm\":[],\"AlignSetting\":[],\"AllowedBluetoothDevice\":[],\"AllowedUsbDevice\":[],\"AlphaOption\":[],\"AnalyserNode\":[\"AudioNode\",\"EventTarget\"],\"AnalyserOptions\":[],\"AngleInstancedArrays\":[],\"Animation\":[\"EventTarget\"],\"AnimationEffect\":[],\"AnimationEvent\":[\"Event\"],\"AnimationEventInit\":[],\"AnimationPlayState\":[],\"AnimationPlaybackEvent\":[\"Event\"],\"AnimationPlaybackEventInit\":[],\"AnimationPropertyDetails\":[],\"AnimationPropertyValueDetails\":[],\"AnimationTimeline\":[],\"AssignedNodesOptions\":[],\"AttestationConveyancePreference\":[],\"Attr\":[\"EventTarget\",\"Node\"],\"AttributeNameValue\":[],\"AudioBuffer\":[],\"AudioBufferOptions\":[],\"AudioBufferSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"AudioBufferSourceOptions\":[],\"AudioConfiguration\":[],\"AudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"AudioContextLatencyCategory\":[],\"AudioContextOptions\":[],\"AudioContextState\":[],\"AudioData\":[],\"AudioDataCopyToOptions\":[],\"AudioDataInit\":[],\"AudioDecoder\":[],\"AudioDecoderConfig\":[],\"AudioDecoderInit\":[],\"AudioDecoderSupport\":[],\"AudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"AudioEncoder\":[],\"AudioEncoderConfig\":[],\"AudioEncoderInit\":[],\"AudioEncoderSupport\":[],\"AudioListener\":[],\"AudioNode\":[\"EventTarget\"],\"AudioNodeOptions\":[],\"AudioParam\":[],\"AudioParamMap\":[],\"AudioProcessingEvent\":[\"Event\"],\"AudioSampleFormat\":[],\"AudioScheduledSourceNode\":[\"AudioNode\",\"EventTarget\"],\"AudioSinkInfo\":[],\"AudioSinkOptions\":[],\"AudioSinkType\":[],\"AudioStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"AudioTrack\":[],\"AudioTrackList\":[\"EventTarget\"],\"AudioWorklet\":[\"Worklet\"],\"AudioWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"AudioWorkletNode\":[\"AudioNode\",\"EventTarget\"],\"AudioWorkletNodeOptions\":[],\"AudioWorkletProcessor\":[],\"AuthenticationExtensionsClientInputs\":[],\"AuthenticationExtensionsClientInputsJson\":[],\"AuthenticationExtensionsClientOutputs\":[],\"AuthenticationExtensionsClientOutputsJson\":[],\"AuthenticationExtensionsDevicePublicKeyInputs\":[],\"AuthenticationExtensionsDevicePublicKeyOutputs\":[],\"AuthenticationExtensionsLargeBlobInputs\":[],\"AuthenticationExtensionsLargeBlobOutputs\":[],\"AuthenticationExtensionsPrfInputs\":[],\"AuthenticationExtensionsPrfOutputs\":[],\"AuthenticationExtensionsPrfValues\":[],\"AuthenticationResponseJson\":[],\"AuthenticatorAssertionResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAssertionResponseJson\":[],\"AuthenticatorAttachment\":[],\"AuthenticatorAttestationResponse\":[\"AuthenticatorResponse\"],\"AuthenticatorAttestationResponseJson\":[],\"AuthenticatorResponse\":[],\"AuthenticatorSelectionCriteria\":[],\"AuthenticatorTransport\":[],\"AutoKeyword\":[],\"AutocompleteInfo\":[],\"BarProp\":[],\"BaseAudioContext\":[\"EventTarget\"],\"BaseComputedKeyframe\":[],\"BaseKeyframe\":[],\"BasePropertyIndexedKeyframe\":[],\"BasicCardRequest\":[],\"BasicCardResponse\":[],\"BasicCardType\":[],\"BatteryManager\":[\"EventTarget\"],\"BeforeUnloadEvent\":[\"Event\"],\"BinaryType\":[],\"BiquadFilterNode\":[\"AudioNode\",\"EventTarget\"],\"BiquadFilterOptions\":[],\"BiquadFilterType\":[],\"Blob\":[],\"BlobEvent\":[\"Event\"],\"BlobEventInit\":[],\"BlobPropertyBag\":[],\"BlockParsingOptions\":[],\"Bluetooth\":[\"EventTarget\"],\"BluetoothAdvertisingEvent\":[\"Event\"],\"BluetoothAdvertisingEventInit\":[],\"BluetoothCharacteristicProperties\":[],\"BluetoothDataFilterInit\":[],\"BluetoothDevice\":[\"EventTarget\"],\"BluetoothLeScanFilterInit\":[],\"BluetoothManufacturerDataMap\":[],\"BluetoothPermissionDescriptor\":[],\"BluetoothPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"BluetoothPermissionStorage\":[],\"BluetoothRemoteGattCharacteristic\":[\"EventTarget\"],\"BluetoothRemoteGattDescriptor\":[],\"BluetoothRemoteGattServer\":[],\"BluetoothRemoteGattService\":[\"EventTarget\"],\"BluetoothServiceDataMap\":[],\"BluetoothUuid\":[],\"BoxQuadOptions\":[],\"BroadcastChannel\":[\"EventTarget\"],\"BrowserElementDownloadOptions\":[],\"BrowserElementExecuteScriptOptions\":[],\"BrowserFeedWriter\":[],\"BrowserFindCaseSensitivity\":[],\"BrowserFindDirection\":[],\"ByteLengthQueuingStrategy\":[],\"Cache\":[],\"CacheBatchOperation\":[],\"CacheQueryOptions\":[],\"CacheStorage\":[],\"CacheStorageNamespace\":[],\"CanvasCaptureMediaStream\":[\"EventTarget\",\"MediaStream\"],\"CanvasCaptureMediaStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"CanvasGradient\":[],\"CanvasPattern\":[],\"CanvasRenderingContext2d\":[],\"CanvasWindingRule\":[],\"CaretChangedReason\":[],\"CaretPosition\":[],\"CaretStateChangedEventInit\":[],\"CdataSection\":[\"CharacterData\",\"EventTarget\",\"Node\",\"Text\"],\"ChannelCountMode\":[],\"ChannelInterpretation\":[],\"ChannelMergerNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelMergerOptions\":[],\"ChannelSplitterNode\":[\"AudioNode\",\"EventTarget\"],\"ChannelSplitterOptions\":[],\"CharacterData\":[\"EventTarget\",\"Node\"],\"CheckerboardReason\":[],\"CheckerboardReport\":[],\"CheckerboardReportService\":[],\"ChromeFilePropertyBag\":[],\"ChromeWorker\":[\"EventTarget\",\"Worker\"],\"Client\":[],\"ClientQueryOptions\":[],\"ClientRectsAndTexts\":[],\"ClientType\":[],\"Clients\":[],\"Clipboard\":[\"EventTarget\"],\"ClipboardEvent\":[\"Event\"],\"ClipboardEventInit\":[],\"ClipboardItem\":[],\"ClipboardItemOptions\":[],\"ClipboardPermissionDescriptor\":[],\"ClipboardUnsanitizedFormats\":[],\"CloseEvent\":[\"Event\"],\"CloseEventInit\":[],\"CodecState\":[],\"CollectedClientData\":[],\"ColorSpaceConversion\":[],\"Comment\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"CompositeOperation\":[],\"CompositionEvent\":[\"Event\",\"UiEvent\"],\"CompositionEventInit\":[],\"CompressionFormat\":[],\"CompressionStream\":[],\"ComputedEffectTiming\":[],\"ConnStatusDict\":[],\"ConnectionType\":[],\"ConsoleCounter\":[],\"ConsoleCounterError\":[],\"ConsoleEvent\":[],\"ConsoleInstance\":[],\"ConsoleInstanceOptions\":[],\"ConsoleLevel\":[],\"ConsoleLogLevel\":[],\"ConsoleProfileEvent\":[],\"ConsoleStackEntry\":[],\"ConsoleTimerError\":[],\"ConsoleTimerLogOrEnd\":[],\"ConsoleTimerStart\":[],\"ConstantSourceNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"ConstantSourceOptions\":[],\"ConstrainBooleanParameters\":[],\"ConstrainDomStringParameters\":[],\"ConstrainDoubleRange\":[],\"ConstrainLongRange\":[],\"ContextAttributes2d\":[],\"ConvertCoordinateOptions\":[],\"ConvolverNode\":[\"AudioNode\",\"EventTarget\"],\"ConvolverOptions\":[],\"CookieChangeEvent\":[\"Event\"],\"CookieChangeEventInit\":[],\"CookieInit\":[],\"CookieListItem\":[],\"CookieSameSite\":[],\"CookieStore\":[\"EventTarget\"],\"CookieStoreDeleteOptions\":[],\"CookieStoreGetOptions\":[],\"CookieStoreManager\":[],\"Coordinates\":[],\"CountQueuingStrategy\":[],\"Credential\":[],\"CredentialCreationOptions\":[],\"CredentialPropertiesOutput\":[],\"CredentialRequestOptions\":[],\"CredentialsContainer\":[],\"Crypto\":[],\"CryptoKey\":[],\"CryptoKeyPair\":[],\"CssAnimation\":[\"Animation\",\"EventTarget\"],\"CssBoxType\":[],\"CssConditionRule\":[\"CssGroupingRule\",\"CssRule\"],\"CssCounterStyleRule\":[\"CssRule\"],\"CssFontFaceRule\":[\"CssRule\"],\"CssFontFeatureValuesRule\":[\"CssRule\"],\"CssGroupingRule\":[\"CssRule\"],\"CssImportRule\":[\"CssRule\"],\"CssKeyframeRule\":[\"CssRule\"],\"CssKeyframesRule\":[\"CssRule\"],\"CssMediaRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssNamespaceRule\":[\"CssRule\"],\"CssPageRule\":[\"CssRule\"],\"CssPseudoElement\":[],\"CssRule\":[],\"CssRuleList\":[],\"CssStyleDeclaration\":[],\"CssStyleRule\":[\"CssRule\"],\"CssStyleSheet\":[\"StyleSheet\"],\"CssStyleSheetParsingMode\":[],\"CssSupportsRule\":[\"CssConditionRule\",\"CssGroupingRule\",\"CssRule\"],\"CssTransition\":[\"Animation\",\"EventTarget\"],\"CustomElementRegistry\":[],\"CustomEvent\":[\"Event\"],\"CustomEventInit\":[],\"DataTransfer\":[],\"DataTransferItem\":[],\"DataTransferItemList\":[],\"DateTimeValue\":[],\"DecoderDoctorNotification\":[],\"DecoderDoctorNotificationType\":[],\"DecompressionStream\":[],\"DedicatedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"DelayNode\":[\"AudioNode\",\"EventTarget\"],\"DelayOptions\":[],\"DeviceAcceleration\":[],\"DeviceAccelerationInit\":[],\"DeviceLightEvent\":[\"Event\"],\"DeviceLightEventInit\":[],\"DeviceMotionEvent\":[\"Event\"],\"DeviceMotionEventInit\":[],\"DeviceOrientationEvent\":[\"Event\"],\"DeviceOrientationEventInit\":[],\"DeviceProximityEvent\":[\"Event\"],\"DeviceProximityEventInit\":[],\"DeviceRotationRate\":[],\"DeviceRotationRateInit\":[],\"DhKeyDeriveParams\":[],\"DirectionSetting\":[],\"Directory\":[],\"DirectoryPickerOptions\":[],\"DisplayMediaStreamConstraints\":[],\"DisplayNameOptions\":[],\"DisplayNameResult\":[],\"DistanceModelType\":[],\"DnsCacheDict\":[],\"DnsCacheEntry\":[],\"DnsLookupDict\":[],\"Document\":[\"EventTarget\",\"Node\"],\"DocumentFragment\":[\"EventTarget\",\"Node\"],\"DocumentTimeline\":[\"AnimationTimeline\"],\"DocumentTimelineOptions\":[],\"DocumentType\":[\"EventTarget\",\"Node\"],\"DomError\":[],\"DomException\":[],\"DomImplementation\":[],\"DomMatrix\":[\"DomMatrixReadOnly\"],\"DomMatrix2dInit\":[],\"DomMatrixInit\":[],\"DomMatrixReadOnly\":[],\"DomParser\":[],\"DomPoint\":[\"DomPointReadOnly\"],\"DomPointInit\":[],\"DomPointReadOnly\":[],\"DomQuad\":[],\"DomQuadInit\":[],\"DomQuadJson\":[],\"DomRect\":[\"DomRectReadOnly\"],\"DomRectInit\":[],\"DomRectList\":[],\"DomRectReadOnly\":[],\"DomRequest\":[\"EventTarget\"],\"DomRequestReadyState\":[],\"DomStringList\":[],\"DomStringMap\":[],\"DomTokenList\":[],\"DomWindowResizeEventDetail\":[],\"DoubleRange\":[],\"DragEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"DragEventInit\":[],\"DynamicsCompressorNode\":[\"AudioNode\",\"EventTarget\"],\"DynamicsCompressorOptions\":[],\"EcKeyAlgorithm\":[],\"EcKeyGenParams\":[],\"EcKeyImportParams\":[],\"EcdhKeyDeriveParams\":[],\"EcdsaParams\":[],\"EffectTiming\":[],\"Element\":[\"EventTarget\",\"Node\"],\"ElementCreationOptions\":[],\"ElementDefinitionOptions\":[],\"EncodedAudioChunk\":[],\"EncodedAudioChunkInit\":[],\"EncodedAudioChunkMetadata\":[],\"EncodedAudioChunkType\":[],\"EncodedVideoChunk\":[],\"EncodedVideoChunkInit\":[],\"EncodedVideoChunkMetadata\":[],\"EncodedVideoChunkType\":[],\"EndingTypes\":[],\"ErrorCallback\":[],\"ErrorEvent\":[\"Event\"],\"ErrorEventInit\":[],\"Event\":[],\"EventInit\":[],\"EventListener\":[],\"EventListenerOptions\":[],\"EventModifierInit\":[],\"EventSource\":[\"EventTarget\"],\"EventSourceInit\":[],\"EventTarget\":[],\"Exception\":[],\"ExtBlendMinmax\":[],\"ExtColorBufferFloat\":[],\"ExtColorBufferHalfFloat\":[],\"ExtDisjointTimerQuery\":[],\"ExtFragDepth\":[],\"ExtSRgb\":[],\"ExtShaderTextureLod\":[],\"ExtTextureFilterAnisotropic\":[],\"ExtTextureNorm16\":[],\"ExtendableCookieChangeEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableCookieChangeEventInit\":[],\"ExtendableEvent\":[\"Event\"],\"ExtendableEventInit\":[],\"ExtendableMessageEvent\":[\"Event\",\"ExtendableEvent\"],\"ExtendableMessageEventInit\":[],\"External\":[],\"FakePluginMimeEntry\":[],\"FakePluginTagInit\":[],\"FetchEvent\":[\"Event\",\"ExtendableEvent\"],\"FetchEventInit\":[],\"FetchObserver\":[\"EventTarget\"],\"FetchReadableStreamReadDataArray\":[],\"FetchReadableStreamReadDataDone\":[],\"FetchState\":[],\"File\":[\"Blob\"],\"FileCallback\":[],\"FileList\":[],\"FilePickerAcceptType\":[],\"FilePickerOptions\":[],\"FilePropertyBag\":[],\"FileReader\":[\"EventTarget\"],\"FileReaderSync\":[],\"FileSystem\":[],\"FileSystemCreateWritableOptions\":[],\"FileSystemDirectoryEntry\":[\"FileSystemEntry\"],\"FileSystemDirectoryHandle\":[\"FileSystemHandle\"],\"FileSystemDirectoryReader\":[],\"FileSystemEntriesCallback\":[],\"FileSystemEntry\":[],\"FileSystemEntryCallback\":[],\"FileSystemFileEntry\":[\"FileSystemEntry\"],\"FileSystemFileHandle\":[\"FileSystemHandle\"],\"FileSystemFlags\":[],\"FileSystemGetDirectoryOptions\":[],\"FileSystemGetFileOptions\":[],\"FileSystemHandle\":[],\"FileSystemHandleKind\":[],\"FileSystemHandlePermissionDescriptor\":[],\"FileSystemPermissionDescriptor\":[],\"FileSystemPermissionMode\":[],\"FileSystemReadWriteOptions\":[],\"FileSystemRemoveOptions\":[],\"FileSystemSyncAccessHandle\":[],\"FileSystemWritableFileStream\":[\"WritableStream\"],\"FillMode\":[],\"FlashClassification\":[],\"FlowControlType\":[],\"FocusEvent\":[\"Event\",\"UiEvent\"],\"FocusEventInit\":[],\"FocusOptions\":[],\"FontData\":[],\"FontFace\":[],\"FontFaceDescriptors\":[],\"FontFaceLoadStatus\":[],\"FontFaceSet\":[\"EventTarget\"],\"FontFaceSetIterator\":[],\"FontFaceSetIteratorResult\":[],\"FontFaceSetLoadEvent\":[\"Event\"],\"FontFaceSetLoadEventInit\":[],\"FontFaceSetLoadStatus\":[],\"FormData\":[],\"FrameType\":[],\"FuzzingFunctions\":[],\"GainNode\":[\"AudioNode\",\"EventTarget\"],\"GainOptions\":[],\"Gamepad\":[],\"GamepadButton\":[],\"GamepadEffectParameters\":[],\"GamepadEvent\":[\"Event\"],\"GamepadEventInit\":[],\"GamepadHand\":[],\"GamepadHapticActuator\":[],\"GamepadHapticActuatorType\":[],\"GamepadHapticEffectType\":[],\"GamepadHapticsResult\":[],\"GamepadMappingType\":[],\"GamepadPose\":[],\"GamepadTouch\":[],\"Geolocation\":[],\"GestureEvent\":[\"Event\",\"UiEvent\"],\"GetAnimationsOptions\":[],\"GetRootNodeOptions\":[],\"GetUserMediaRequest\":[],\"Gpu\":[],\"GpuAdapter\":[],\"GpuAdapterInfo\":[],\"GpuAddressMode\":[],\"GpuAutoLayoutMode\":[],\"GpuBindGroup\":[],\"GpuBindGroupDescriptor\":[],\"GpuBindGroupEntry\":[],\"GpuBindGroupLayout\":[],\"GpuBindGroupLayoutDescriptor\":[],\"GpuBindGroupLayoutEntry\":[],\"GpuBlendComponent\":[],\"GpuBlendFactor\":[],\"GpuBlendOperation\":[],\"GpuBlendState\":[],\"GpuBuffer\":[],\"GpuBufferBinding\":[],\"GpuBufferBindingLayout\":[],\"GpuBufferBindingType\":[],\"GpuBufferDescriptor\":[],\"GpuBufferMapState\":[],\"GpuCanvasAlphaMode\":[],\"GpuCanvasConfiguration\":[],\"GpuCanvasContext\":[],\"GpuCanvasToneMapping\":[],\"GpuCanvasToneMappingMode\":[],\"GpuColorDict\":[],\"GpuColorTargetState\":[],\"GpuCommandBuffer\":[],\"GpuCommandBufferDescriptor\":[],\"GpuCommandEncoder\":[],\"GpuCommandEncoderDescriptor\":[],\"GpuCompareFunction\":[],\"GpuCompilationInfo\":[],\"GpuCompilationMessage\":[],\"GpuCompilationMessageType\":[],\"GpuComputePassDescriptor\":[],\"GpuComputePassEncoder\":[],\"GpuComputePassTimestampWrites\":[],\"GpuComputePipeline\":[],\"GpuComputePipelineDescriptor\":[],\"GpuCopyExternalImageDestInfo\":[],\"GpuCopyExternalImageSourceInfo\":[],\"GpuCullMode\":[],\"GpuDepthStencilState\":[],\"GpuDevice\":[\"EventTarget\"],\"GpuDeviceDescriptor\":[],\"GpuDeviceLostInfo\":[],\"GpuDeviceLostReason\":[],\"GpuError\":[],\"GpuErrorFilter\":[],\"GpuExtent3dDict\":[],\"GpuExternalTexture\":[],\"GpuExternalTextureBindingLayout\":[],\"GpuExternalTextureDescriptor\":[],\"GpuFeatureName\":[],\"GpuFilterMode\":[],\"GpuFragmentState\":[],\"GpuFrontFace\":[],\"GpuIndexFormat\":[],\"GpuInternalError\":[\"GpuError\"],\"GpuLoadOp\":[],\"GpuMipmapFilterMode\":[],\"GpuMultisampleState\":[],\"GpuObjectDescriptorBase\":[],\"GpuOrigin2dDict\":[],\"GpuOrigin3dDict\":[],\"GpuOutOfMemoryError\":[\"GpuError\"],\"GpuPipelineDescriptorBase\":[],\"GpuPipelineError\":[\"DomException\"],\"GpuPipelineErrorInit\":[],\"GpuPipelineErrorReason\":[],\"GpuPipelineLayout\":[],\"GpuPipelineLayoutDescriptor\":[],\"GpuPowerPreference\":[],\"GpuPrimitiveState\":[],\"GpuPrimitiveTopology\":[],\"GpuProgrammableStage\":[],\"GpuQuerySet\":[],\"GpuQuerySetDescriptor\":[],\"GpuQueryType\":[],\"GpuQueue\":[],\"GpuQueueDescriptor\":[],\"GpuRenderBundle\":[],\"GpuRenderBundleDescriptor\":[],\"GpuRenderBundleEncoder\":[],\"GpuRenderBundleEncoderDescriptor\":[],\"GpuRenderPassColorAttachment\":[],\"GpuRenderPassDepthStencilAttachment\":[],\"GpuRenderPassDescriptor\":[],\"GpuRenderPassEncoder\":[],\"GpuRenderPassLayout\":[],\"GpuRenderPassTimestampWrites\":[],\"GpuRenderPipeline\":[],\"GpuRenderPipelineDescriptor\":[],\"GpuRequestAdapterOptions\":[],\"GpuSampler\":[],\"GpuSamplerBindingLayout\":[],\"GpuSamplerBindingType\":[],\"GpuSamplerDescriptor\":[],\"GpuShaderModule\":[],\"GpuShaderModuleCompilationHint\":[],\"GpuShaderModuleDescriptor\":[],\"GpuStencilFaceState\":[],\"GpuStencilOperation\":[],\"GpuStorageTextureAccess\":[],\"GpuStorageTextureBindingLayout\":[],\"GpuStoreOp\":[],\"GpuSupportedFeatures\":[],\"GpuSupportedLimits\":[],\"GpuTexelCopyBufferInfo\":[],\"GpuTexelCopyBufferLayout\":[],\"GpuTexelCopyTextureInfo\":[],\"GpuTexture\":[],\"GpuTextureAspect\":[],\"GpuTextureBindingLayout\":[],\"GpuTextureDescriptor\":[],\"GpuTextureDimension\":[],\"GpuTextureFormat\":[],\"GpuTextureSampleType\":[],\"GpuTextureView\":[],\"GpuTextureViewDescriptor\":[],\"GpuTextureViewDimension\":[],\"GpuUncapturedErrorEvent\":[\"Event\"],\"GpuUncapturedErrorEventInit\":[],\"GpuValidationError\":[\"GpuError\"],\"GpuVertexAttribute\":[],\"GpuVertexBufferLayout\":[],\"GpuVertexFormat\":[],\"GpuVertexState\":[],\"GpuVertexStepMode\":[],\"GroupedHistoryEventInit\":[],\"HalfOpenInfoDict\":[],\"HardwareAcceleration\":[],\"HashChangeEvent\":[\"Event\"],\"HashChangeEventInit\":[],\"Headers\":[],\"HeadersGuardEnum\":[],\"Hid\":[\"EventTarget\"],\"HidCollectionInfo\":[],\"HidConnectionEvent\":[\"Event\"],\"HidConnectionEventInit\":[],\"HidDevice\":[\"EventTarget\"],\"HidDeviceFilter\":[],\"HidDeviceRequestOptions\":[],\"HidInputReportEvent\":[\"Event\"],\"HidInputReportEventInit\":[],\"HidReportInfo\":[],\"HidReportItem\":[],\"HidUnitSystem\":[],\"HiddenPluginEventInit\":[],\"History\":[],\"HitRegionOptions\":[],\"HkdfParams\":[],\"HmacDerivedKeyParams\":[],\"HmacImportParams\":[],\"HmacKeyAlgorithm\":[],\"HmacKeyGenParams\":[],\"HtmlAllCollection\":[],\"HtmlAnchorElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlAudioElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HtmlBaseElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBodyElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlBrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlButtonElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCanvasElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlCollection\":[],\"HtmlDListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDataListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDetailsElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDialogElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDirectoryElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDivElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"HtmlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"HtmlEmbedElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFieldSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFontElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFormControlsCollection\":[\"HtmlCollection\"],\"HtmlFormElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlFrameSetElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHeadingElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHrElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlHtmlElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlIFrameElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlImageElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlInputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLabelElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLegendElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLiElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlLinkElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMapElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMediaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMenuItemElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMetaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlMeterElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlModElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlObjectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptGroupElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlOptionsCollection\":[\"HtmlCollection\"],\"HtmlOutputElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParagraphElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlParamElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPictureElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlPreElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlProgressElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlQuoteElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlScriptElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSelectElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSlotElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSourceElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlSpanElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlStyleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCaptionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableCellElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableColElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableRowElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTableSectionElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTemplateElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTextAreaElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTimeElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTitleElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlTrackElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUListElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlUnknownElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"Node\"],\"HtmlVideoElement\":[\"Element\",\"EventTarget\",\"HtmlElement\",\"HtmlMediaElement\",\"Node\"],\"HttpConnDict\":[],\"HttpConnInfo\":[],\"HttpConnectionElement\":[],\"IdbCursor\":[],\"IdbCursorDirection\":[],\"IdbCursorWithValue\":[\"IdbCursor\"],\"IdbDatabase\":[\"EventTarget\"],\"IdbFactory\":[],\"IdbFileHandle\":[\"EventTarget\"],\"IdbFileMetadataParameters\":[],\"IdbFileRequest\":[\"DomRequest\",\"EventTarget\"],\"IdbIndex\":[],\"IdbIndexParameters\":[],\"IdbKeyRange\":[],\"IdbLocaleAwareKeyRange\":[\"IdbKeyRange\"],\"IdbMutableFile\":[\"EventTarget\"],\"IdbObjectStore\":[],\"IdbObjectStoreParameters\":[],\"IdbOpenDbOptions\":[],\"IdbOpenDbRequest\":[\"EventTarget\",\"IdbRequest\"],\"IdbRequest\":[\"EventTarget\"],\"IdbRequestReadyState\":[],\"IdbTransaction\":[\"EventTarget\"],\"IdbTransactionDurability\":[],\"IdbTransactionMode\":[],\"IdbTransactionOptions\":[],\"IdbVersionChangeEvent\":[\"Event\"],\"IdbVersionChangeEventInit\":[],\"IdleDeadline\":[],\"IdleRequestOptions\":[],\"IirFilterNode\":[\"AudioNode\",\"EventTarget\"],\"IirFilterOptions\":[],\"ImageBitmap\":[],\"ImageBitmapOptions\":[],\"ImageBitmapRenderingContext\":[],\"ImageCapture\":[],\"ImageCaptureError\":[],\"ImageCaptureErrorEvent\":[\"Event\"],\"ImageCaptureErrorEventInit\":[],\"ImageData\":[],\"ImageDecodeOptions\":[],\"ImageDecodeResult\":[],\"ImageDecoder\":[],\"ImageDecoderInit\":[],\"ImageEncodeOptions\":[],\"ImageOrientation\":[],\"ImageTrack\":[\"EventTarget\"],\"ImageTrackList\":[],\"InputDeviceInfo\":[\"MediaDeviceInfo\"],\"InputEvent\":[\"Event\",\"UiEvent\"],\"InputEventInit\":[],\"IntersectionObserver\":[],\"IntersectionObserverEntry\":[],\"IntersectionObserverEntryInit\":[],\"IntersectionObserverInit\":[],\"IntlUtils\":[],\"IsInputPendingOptions\":[],\"IterableKeyAndValueResult\":[],\"IterableKeyOrValueResult\":[],\"IterationCompositeOperation\":[],\"JsonWebKey\":[],\"KeyAlgorithm\":[],\"KeyEvent\":[],\"KeyFrameRequestEvent\":[\"Event\"],\"KeyIdsInitData\":[],\"KeyboardEvent\":[\"Event\",\"UiEvent\"],\"KeyboardEventInit\":[],\"KeyframeAnimationOptions\":[],\"KeyframeEffect\":[\"AnimationEffect\"],\"KeyframeEffectOptions\":[],\"L10nElement\":[],\"L10nValue\":[],\"LargeBlobSupport\":[],\"LatencyMode\":[],\"LifecycleCallbacks\":[],\"LineAlignSetting\":[],\"ListBoxObject\":[],\"LocalMediaStream\":[\"EventTarget\",\"MediaStream\"],\"LocaleInfo\":[],\"Location\":[],\"Lock\":[],\"LockInfo\":[],\"LockManager\":[],\"LockManagerSnapshot\":[],\"LockMode\":[],\"LockOptions\":[],\"MathMlElement\":[\"Element\",\"EventTarget\",\"Node\"],\"MediaCapabilities\":[],\"MediaCapabilitiesInfo\":[],\"MediaConfiguration\":[],\"MediaDecodingConfiguration\":[],\"MediaDecodingType\":[],\"MediaDeviceInfo\":[],\"MediaDeviceKind\":[],\"MediaDevices\":[\"EventTarget\"],\"MediaElementAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaElementAudioSourceOptions\":[],\"MediaEncodingConfiguration\":[],\"MediaEncodingType\":[],\"MediaEncryptedEvent\":[\"Event\"],\"MediaError\":[],\"MediaImage\":[],\"MediaKeyError\":[\"Event\"],\"MediaKeyMessageEvent\":[\"Event\"],\"MediaKeyMessageEventInit\":[],\"MediaKeyMessageType\":[],\"MediaKeyNeededEventInit\":[],\"MediaKeySession\":[\"EventTarget\"],\"MediaKeySessionType\":[],\"MediaKeyStatus\":[],\"MediaKeyStatusMap\":[],\"MediaKeySystemAccess\":[],\"MediaKeySystemConfiguration\":[],\"MediaKeySystemMediaCapability\":[],\"MediaKeySystemStatus\":[],\"MediaKeys\":[],\"MediaKeysPolicy\":[],\"MediaKeysRequirement\":[],\"MediaList\":[],\"MediaMetadata\":[],\"MediaMetadataInit\":[],\"MediaPositionState\":[],\"MediaQueryList\":[\"EventTarget\"],\"MediaQueryListEvent\":[\"Event\"],\"MediaQueryListEventInit\":[],\"MediaRecorder\":[\"EventTarget\"],\"MediaRecorderErrorEvent\":[\"Event\"],\"MediaRecorderErrorEventInit\":[],\"MediaRecorderOptions\":[],\"MediaSession\":[],\"MediaSessionAction\":[],\"MediaSessionActionDetails\":[],\"MediaSessionPlaybackState\":[],\"MediaSource\":[\"EventTarget\"],\"MediaSourceEndOfStreamError\":[],\"MediaSourceEnum\":[],\"MediaSourceReadyState\":[],\"MediaStream\":[\"EventTarget\"],\"MediaStreamAudioDestinationNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceNode\":[\"AudioNode\",\"EventTarget\"],\"MediaStreamAudioSourceOptions\":[],\"MediaStreamConstraints\":[],\"MediaStreamError\":[],\"MediaStreamEvent\":[\"Event\"],\"MediaStreamEventInit\":[],\"MediaStreamTrack\":[\"EventTarget\"],\"MediaStreamTrackEvent\":[\"Event\"],\"MediaStreamTrackEventInit\":[],\"MediaStreamTrackGenerator\":[\"EventTarget\",\"MediaStreamTrack\"],\"MediaStreamTrackGeneratorInit\":[],\"MediaStreamTrackProcessor\":[],\"MediaStreamTrackProcessorInit\":[],\"MediaStreamTrackState\":[],\"MediaTrackCapabilities\":[],\"MediaTrackConstraintSet\":[],\"MediaTrackConstraints\":[],\"MediaTrackSettings\":[],\"MediaTrackSupportedConstraints\":[],\"MemoryAttribution\":[],\"MemoryAttributionContainer\":[],\"MemoryBreakdownEntry\":[],\"MemoryMeasurement\":[],\"MessageChannel\":[],\"MessageEvent\":[\"Event\"],\"MessageEventInit\":[],\"MessagePort\":[\"EventTarget\"],\"MidiAccess\":[\"EventTarget\"],\"MidiConnectionEvent\":[\"Event\"],\"MidiConnectionEventInit\":[],\"MidiInput\":[\"EventTarget\",\"MidiPort\"],\"MidiInputMap\":[],\"MidiMessageEvent\":[\"Event\"],\"MidiMessageEventInit\":[],\"MidiOptions\":[],\"MidiOutput\":[\"EventTarget\",\"MidiPort\"],\"MidiOutputMap\":[],\"MidiPort\":[\"EventTarget\"],\"MidiPortConnectionState\":[],\"MidiPortDeviceState\":[],\"MidiPortType\":[],\"MimeType\":[],\"MimeTypeArray\":[],\"MouseEvent\":[\"Event\",\"UiEvent\"],\"MouseEventInit\":[],\"MouseScrollEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"MozDebug\":[],\"MutationEvent\":[\"Event\"],\"MutationObserver\":[],\"MutationObserverInit\":[],\"MutationObservingInfo\":[],\"MutationRecord\":[],\"NamedNodeMap\":[],\"NativeOsFileReadOptions\":[],\"NativeOsFileWriteAtomicOptions\":[],\"NavigationType\":[],\"Navigator\":[],\"NavigatorAutomationInformation\":[],\"NavigatorUaBrandVersion\":[],\"NavigatorUaData\":[],\"NetworkCommandOptions\":[],\"NetworkInformation\":[\"EventTarget\"],\"NetworkResultOptions\":[],\"Node\":[\"EventTarget\"],\"NodeFilter\":[],\"NodeIterator\":[],\"NodeList\":[],\"Notification\":[\"EventTarget\"],\"NotificationAction\":[],\"NotificationDirection\":[],\"NotificationEvent\":[\"Event\",\"ExtendableEvent\"],\"NotificationEventInit\":[],\"NotificationOptions\":[],\"NotificationPermission\":[],\"ObserverCallback\":[],\"OesElementIndexUint\":[],\"OesStandardDerivatives\":[],\"OesTextureFloat\":[],\"OesTextureFloatLinear\":[],\"OesTextureHalfFloat\":[],\"OesTextureHalfFloatLinear\":[],\"OesVertexArrayObject\":[],\"OfflineAudioCompletionEvent\":[\"Event\"],\"OfflineAudioCompletionEventInit\":[],\"OfflineAudioContext\":[\"BaseAudioContext\",\"EventTarget\"],\"OfflineAudioContextOptions\":[],\"OfflineResourceList\":[\"EventTarget\"],\"OffscreenCanvas\":[\"EventTarget\"],\"OffscreenCanvasRenderingContext2d\":[],\"OpenFilePickerOptions\":[],\"OpenWindowEventDetail\":[],\"OptionalEffectTiming\":[],\"OrientationLockType\":[],\"OrientationType\":[],\"OscillatorNode\":[\"AudioNode\",\"AudioScheduledSourceNode\",\"EventTarget\"],\"OscillatorOptions\":[],\"OscillatorType\":[],\"OverSampleType\":[],\"OvrMultiview2\":[],\"PageTransitionEvent\":[\"Event\"],\"PageTransitionEventInit\":[],\"PaintRequest\":[],\"PaintRequestList\":[],\"PaintWorkletGlobalScope\":[\"WorkletGlobalScope\"],\"PannerNode\":[\"AudioNode\",\"EventTarget\"],\"PannerOptions\":[],\"PanningModelType\":[],\"ParityType\":[],\"Path2d\":[],\"PaymentAddress\":[],\"PaymentComplete\":[],\"PaymentMethodChangeEvent\":[\"Event\",\"PaymentRequestUpdateEvent\"],\"PaymentMethodChangeEventInit\":[],\"PaymentRequestUpdateEvent\":[\"Event\"],\"PaymentRequestUpdateEventInit\":[],\"PaymentResponse\":[],\"Pbkdf2Params\":[],\"PcImplIceConnectionState\":[],\"PcImplIceGatheringState\":[],\"PcImplSignalingState\":[],\"PcObserverStateType\":[],\"Performance\":[\"EventTarget\"],\"PerformanceEntry\":[],\"PerformanceEntryEventInit\":[],\"PerformanceEntryFilterOptions\":[],\"PerformanceMark\":[\"PerformanceEntry\"],\"PerformanceMeasure\":[\"PerformanceEntry\"],\"PerformanceNavigation\":[],\"PerformanceNavigationTiming\":[\"PerformanceEntry\",\"PerformanceResourceTiming\"],\"PerformanceObserver\":[],\"PerformanceObserverEntryList\":[],\"PerformanceObserverInit\":[],\"PerformanceResourceTiming\":[\"PerformanceEntry\"],\"PerformanceServerTiming\":[],\"PerformanceTiming\":[],\"PeriodicWave\":[],\"PeriodicWaveConstraints\":[],\"PeriodicWaveOptions\":[],\"PermissionDescriptor\":[],\"PermissionName\":[],\"PermissionState\":[],\"PermissionStatus\":[\"EventTarget\"],\"Permissions\":[],\"PictureInPictureEvent\":[\"Event\"],\"PictureInPictureEventInit\":[],\"PictureInPictureWindow\":[\"EventTarget\"],\"PlaneLayout\":[],\"PlaybackDirection\":[],\"Plugin\":[],\"PluginArray\":[],\"PluginCrashedEventInit\":[],\"PointerEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"PointerEventInit\":[],\"PopStateEvent\":[\"Event\"],\"PopStateEventInit\":[],\"PopupBlockedEvent\":[\"Event\"],\"PopupBlockedEventInit\":[],\"Position\":[],\"PositionAlignSetting\":[],\"PositionError\":[],\"PositionOptions\":[],\"PremultiplyAlpha\":[],\"Presentation\":[],\"PresentationAvailability\":[\"EventTarget\"],\"PresentationConnection\":[\"EventTarget\"],\"PresentationConnectionAvailableEvent\":[\"Event\"],\"PresentationConnectionAvailableEventInit\":[],\"PresentationConnectionBinaryType\":[],\"PresentationConnectionCloseEvent\":[\"Event\"],\"PresentationConnectionCloseEventInit\":[],\"PresentationConnectionClosedReason\":[],\"PresentationConnectionList\":[\"EventTarget\"],\"PresentationConnectionState\":[],\"PresentationReceiver\":[],\"PresentationRequest\":[\"EventTarget\"],\"PresentationStyle\":[],\"ProcessingInstruction\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"ProfileTimelineLayerRect\":[],\"ProfileTimelineMarker\":[],\"ProfileTimelineMessagePortOperationType\":[],\"ProfileTimelineStackFrame\":[],\"ProfileTimelineWorkerOperationType\":[],\"ProgressEvent\":[\"Event\"],\"ProgressEventInit\":[],\"PromiseNativeHandler\":[],\"PromiseRejectionEvent\":[\"Event\"],\"PromiseRejectionEventInit\":[],\"PublicKeyCredential\":[\"Credential\"],\"PublicKeyCredentialCreationOptions\":[],\"PublicKeyCredentialCreationOptionsJson\":[],\"PublicKeyCredentialDescriptor\":[],\"PublicKeyCredentialDescriptorJson\":[],\"PublicKeyCredentialEntity\":[],\"PublicKeyCredentialHints\":[],\"PublicKeyCredentialParameters\":[],\"PublicKeyCredentialRequestOptions\":[],\"PublicKeyCredentialRequestOptionsJson\":[],\"PublicKeyCredentialRpEntity\":[],\"PublicKeyCredentialType\":[],\"PublicKeyCredentialUserEntity\":[],\"PublicKeyCredentialUserEntityJson\":[],\"PushEncryptionKeyName\":[],\"PushEvent\":[\"Event\",\"ExtendableEvent\"],\"PushEventInit\":[],\"PushManager\":[],\"PushMessageData\":[],\"PushPermissionState\":[],\"PushSubscription\":[],\"PushSubscriptionInit\":[],\"PushSubscriptionJson\":[],\"PushSubscriptionKeys\":[],\"PushSubscriptionOptions\":[],\"PushSubscriptionOptionsInit\":[],\"QueryOptions\":[],\"QueuingStrategy\":[],\"QueuingStrategyInit\":[],\"RadioNodeList\":[\"NodeList\"],\"Range\":[],\"RcwnPerfStats\":[],\"RcwnStatus\":[],\"ReadableByteStreamController\":[],\"ReadableStream\":[],\"ReadableStreamByobReader\":[],\"ReadableStreamByobRequest\":[],\"ReadableStreamDefaultController\":[],\"ReadableStreamDefaultReader\":[],\"ReadableStreamGetReaderOptions\":[],\"ReadableStreamIteratorOptions\":[],\"ReadableStreamReadResult\":[],\"ReadableStreamReaderMode\":[],\"ReadableStreamType\":[],\"ReadableWritablePair\":[],\"RecordingState\":[],\"ReferrerPolicy\":[],\"RegisterRequest\":[],\"RegisterResponse\":[],\"RegisteredKey\":[],\"RegistrationOptions\":[],\"RegistrationResponseJson\":[],\"Request\":[],\"RequestCache\":[],\"RequestCredentials\":[],\"RequestDestination\":[],\"RequestDeviceOptions\":[],\"RequestInit\":[],\"RequestMediaKeySystemAccessNotification\":[],\"RequestMode\":[],\"RequestRedirect\":[],\"ResidentKeyRequirement\":[],\"ResizeObserver\":[],\"ResizeObserverBoxOptions\":[],\"ResizeObserverEntry\":[],\"ResizeObserverOptions\":[],\"ResizeObserverSize\":[],\"ResizeQuality\":[],\"Response\":[],\"ResponseInit\":[],\"ResponseType\":[],\"RsaHashedImportParams\":[],\"RsaOaepParams\":[],\"RsaOtherPrimesInfo\":[],\"RsaPssParams\":[],\"RtcAnswerOptions\":[],\"RtcBundlePolicy\":[],\"RtcCertificate\":[],\"RtcCertificateExpiration\":[],\"RtcCodecStats\":[],\"RtcConfiguration\":[],\"RtcDataChannel\":[\"EventTarget\"],\"RtcDataChannelEvent\":[\"Event\"],\"RtcDataChannelEventInit\":[],\"RtcDataChannelInit\":[],\"RtcDataChannelState\":[],\"RtcDataChannelType\":[],\"RtcDegradationPreference\":[],\"RtcEncodedAudioFrame\":[],\"RtcEncodedAudioFrameMetadata\":[],\"RtcEncodedAudioFrameOptions\":[],\"RtcEncodedVideoFrame\":[],\"RtcEncodedVideoFrameMetadata\":[],\"RtcEncodedVideoFrameOptions\":[],\"RtcEncodedVideoFrameType\":[],\"RtcFecParameters\":[],\"RtcIceCandidate\":[],\"RtcIceCandidateInit\":[],\"RtcIceCandidatePairStats\":[],\"RtcIceCandidateStats\":[],\"RtcIceComponentStats\":[],\"RtcIceConnectionState\":[],\"RtcIceCredentialType\":[],\"RtcIceGatheringState\":[],\"RtcIceServer\":[],\"RtcIceTransportPolicy\":[],\"RtcIdentityAssertion\":[],\"RtcIdentityAssertionResult\":[],\"RtcIdentityProvider\":[],\"RtcIdentityProviderDetails\":[],\"RtcIdentityProviderOptions\":[],\"RtcIdentityProviderRegistrar\":[],\"RtcIdentityValidationResult\":[],\"RtcInboundRtpStreamStats\":[],\"RtcMediaStreamStats\":[],\"RtcMediaStreamTrackStats\":[],\"RtcOfferAnswerOptions\":[],\"RtcOfferOptions\":[],\"RtcOutboundRtpStreamStats\":[],\"RtcPeerConnection\":[\"EventTarget\"],\"RtcPeerConnectionIceErrorEvent\":[\"Event\"],\"RtcPeerConnectionIceEvent\":[\"Event\"],\"RtcPeerConnectionIceEventInit\":[],\"RtcPeerConnectionState\":[],\"RtcPriorityType\":[],\"RtcRtcpParameters\":[],\"RtcRtpCapabilities\":[],\"RtcRtpCodecCapability\":[],\"RtcRtpCodecParameters\":[],\"RtcRtpContributingSource\":[],\"RtcRtpEncodingParameters\":[],\"RtcRtpHeaderExtensionCapability\":[],\"RtcRtpHeaderExtensionParameters\":[],\"RtcRtpParameters\":[],\"RtcRtpReceiver\":[],\"RtcRtpScriptTransform\":[],\"RtcRtpScriptTransformer\":[\"EventTarget\"],\"RtcRtpSender\":[],\"RtcRtpSourceEntry\":[],\"RtcRtpSourceEntryType\":[],\"RtcRtpSynchronizationSource\":[],\"RtcRtpTransceiver\":[],\"RtcRtpTransceiverDirection\":[],\"RtcRtpTransceiverInit\":[],\"RtcRtxParameters\":[],\"RtcSdpType\":[],\"RtcSessionDescription\":[],\"RtcSessionDescriptionInit\":[],\"RtcSignalingState\":[],\"RtcStats\":[],\"RtcStatsIceCandidatePairState\":[],\"RtcStatsIceCandidateType\":[],\"RtcStatsReport\":[],\"RtcStatsReportInternal\":[],\"RtcStatsType\":[],\"RtcTrackEvent\":[\"Event\"],\"RtcTrackEventInit\":[],\"RtcTransformEvent\":[\"Event\"],\"RtcTransportStats\":[],\"RtcdtmfSender\":[\"EventTarget\"],\"RtcdtmfToneChangeEvent\":[\"Event\"],\"RtcdtmfToneChangeEventInit\":[],\"RtcrtpContributingSourceStats\":[],\"RtcrtpStreamStats\":[],\"SFrameTransform\":[\"EventTarget\"],\"SFrameTransformErrorEvent\":[\"Event\"],\"SFrameTransformErrorEventInit\":[],\"SFrameTransformErrorEventType\":[],\"SFrameTransformOptions\":[],\"SFrameTransformRole\":[],\"SaveFilePickerOptions\":[],\"Scheduler\":[],\"SchedulerPostTaskOptions\":[],\"Scheduling\":[],\"Screen\":[\"EventTarget\"],\"ScreenColorGamut\":[],\"ScreenLuminance\":[],\"ScreenOrientation\":[\"EventTarget\"],\"ScriptProcessorNode\":[\"AudioNode\",\"EventTarget\"],\"ScrollAreaEvent\":[\"Event\",\"UiEvent\"],\"ScrollBehavior\":[],\"ScrollBoxObject\":[],\"ScrollIntoViewOptions\":[],\"ScrollLogicalPosition\":[],\"ScrollOptions\":[],\"ScrollRestoration\":[],\"ScrollSetting\":[],\"ScrollState\":[],\"ScrollToOptions\":[],\"ScrollViewChangeEventInit\":[],\"SecurityPolicyViolationEvent\":[\"Event\"],\"SecurityPolicyViolationEventDisposition\":[],\"SecurityPolicyViolationEventInit\":[],\"Selection\":[],\"SelectionMode\":[],\"Serial\":[\"EventTarget\"],\"SerialInputSignals\":[],\"SerialOptions\":[],\"SerialOutputSignals\":[],\"SerialPort\":[\"EventTarget\"],\"SerialPortFilter\":[],\"SerialPortInfo\":[],\"SerialPortRequestOptions\":[],\"ServerSocketOptions\":[],\"ServiceWorker\":[\"EventTarget\"],\"ServiceWorkerContainer\":[\"EventTarget\"],\"ServiceWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"ServiceWorkerRegistration\":[\"EventTarget\"],\"ServiceWorkerState\":[],\"ServiceWorkerUpdateViaCache\":[],\"ShadowRoot\":[\"DocumentFragment\",\"EventTarget\",\"Node\"],\"ShadowRootInit\":[],\"ShadowRootMode\":[],\"ShareData\":[],\"SharedWorker\":[\"EventTarget\"],\"SharedWorkerGlobalScope\":[\"EventTarget\",\"WorkerGlobalScope\"],\"SignResponse\":[],\"SocketElement\":[],\"SocketOptions\":[],\"SocketReadyState\":[],\"SocketsDict\":[],\"SourceBuffer\":[\"EventTarget\"],\"SourceBufferAppendMode\":[],\"SourceBufferList\":[\"EventTarget\"],\"SpeechGrammar\":[],\"SpeechGrammarList\":[],\"SpeechRecognition\":[\"EventTarget\"],\"SpeechRecognitionAlternative\":[],\"SpeechRecognitionError\":[\"Event\"],\"SpeechRecognitionErrorCode\":[],\"SpeechRecognitionErrorInit\":[],\"SpeechRecognitionEvent\":[\"Event\"],\"SpeechRecognitionEventInit\":[],\"SpeechRecognitionResult\":[],\"SpeechRecognitionResultList\":[],\"SpeechSynthesis\":[\"EventTarget\"],\"SpeechSynthesisErrorCode\":[],\"SpeechSynthesisErrorEvent\":[\"Event\",\"SpeechSynthesisEvent\"],\"SpeechSynthesisErrorEventInit\":[],\"SpeechSynthesisEvent\":[\"Event\"],\"SpeechSynthesisEventInit\":[],\"SpeechSynthesisUtterance\":[\"EventTarget\"],\"SpeechSynthesisVoice\":[],\"StereoPannerNode\":[\"AudioNode\",\"EventTarget\"],\"StereoPannerOptions\":[],\"Storage\":[],\"StorageEstimate\":[],\"StorageEvent\":[\"Event\"],\"StorageEventInit\":[],\"StorageManager\":[],\"StorageType\":[],\"StreamPipeOptions\":[],\"StyleRuleChangeEventInit\":[],\"StyleSheet\":[],\"StyleSheetApplicableStateChangeEventInit\":[],\"StyleSheetChangeEventInit\":[],\"StyleSheetList\":[],\"SubmitEvent\":[\"Event\"],\"SubmitEventInit\":[],\"SubtleCrypto\":[],\"SupportedType\":[],\"SvcOutputMetadata\":[],\"SvgAngle\":[],\"SvgAnimateElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateMotionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimateTransformElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgAnimatedAngle\":[],\"SvgAnimatedBoolean\":[],\"SvgAnimatedEnumeration\":[],\"SvgAnimatedInteger\":[],\"SvgAnimatedLength\":[],\"SvgAnimatedLengthList\":[],\"SvgAnimatedNumber\":[],\"SvgAnimatedNumberList\":[],\"SvgAnimatedPreserveAspectRatio\":[],\"SvgAnimatedRect\":[],\"SvgAnimatedString\":[],\"SvgAnimatedTransformList\":[],\"SvgAnimationElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgBoundingBoxOptions\":[],\"SvgCircleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgClipPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgComponentTransferFunctionElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgDefsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgDescElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgElement\":[\"Element\",\"EventTarget\",\"Node\"],\"SvgEllipseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgFilterElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgForeignObjectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGeometryElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgGraphicsElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgLength\":[],\"SvgLengthList\":[],\"SvgLineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgLinearGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgMarkerElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMaskElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgMatrix\":[],\"SvgMetadataElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgNumber\":[],\"SvgNumberList\":[],\"SvgPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPathSeg\":[],\"SvgPathSegArcAbs\":[\"SvgPathSeg\"],\"SvgPathSegArcRel\":[\"SvgPathSeg\"],\"SvgPathSegClosePath\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoCubicSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticRel\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothAbs\":[\"SvgPathSeg\"],\"SvgPathSegCurvetoQuadraticSmoothRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoHorizontalRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoRel\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalAbs\":[\"SvgPathSeg\"],\"SvgPathSegLinetoVerticalRel\":[\"SvgPathSeg\"],\"SvgPathSegList\":[],\"SvgPathSegMovetoAbs\":[\"SvgPathSeg\"],\"SvgPathSegMovetoRel\":[\"SvgPathSeg\"],\"SvgPatternElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgPoint\":[],\"SvgPointList\":[],\"SvgPolygonElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPolylineElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgPreserveAspectRatio\":[],\"SvgRadialGradientElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGradientElement\"],\"SvgRect\":[],\"SvgRectElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGeometryElement\",\"SvgGraphicsElement\"],\"SvgScriptElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgAnimationElement\",\"SvgElement\"],\"SvgStopElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgStringList\":[],\"SvgStyleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgSwitchElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgSymbolElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTextContentElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgTextElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"SvgTextPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTextPositioningElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\"],\"SvgTitleElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgTransform\":[],\"SvgTransformList\":[],\"SvgUnitTypes\":[],\"SvgUseElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgViewElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgZoomAndPan\":[],\"SvgaElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgfeBlendElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeColorMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeComponentTransferElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeCompositeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeConvolveMatrixElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDiffuseLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDisplacementMapElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDistantLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeDropShadowElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFloodElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeFuncAElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncBElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncGElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeFuncRElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgComponentTransferFunctionElement\",\"SvgElement\"],\"SvgfeGaussianBlurElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeImageElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMergeNodeElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeMorphologyElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeOffsetElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfePointLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpecularLightingElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeSpotLightElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTileElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgfeTurbulenceElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvggElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgmPathElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\"],\"SvgsvgElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\"],\"SvgtSpanElement\":[\"Element\",\"EventTarget\",\"Node\",\"SvgElement\",\"SvgGraphicsElement\",\"SvgTextContentElement\",\"SvgTextPositioningElement\"],\"TaskController\":[\"AbortController\"],\"TaskControllerInit\":[],\"TaskPriority\":[],\"TaskPriorityChangeEvent\":[\"Event\"],\"TaskPriorityChangeEventInit\":[],\"TaskSignal\":[\"AbortSignal\",\"EventTarget\"],\"TaskSignalAnyInit\":[],\"TcpReadyState\":[],\"TcpServerSocket\":[\"EventTarget\"],\"TcpServerSocketEvent\":[\"Event\"],\"TcpServerSocketEventInit\":[],\"TcpSocket\":[\"EventTarget\"],\"TcpSocketBinaryType\":[],\"TcpSocketErrorEvent\":[\"Event\"],\"TcpSocketErrorEventInit\":[],\"TcpSocketEvent\":[\"Event\"],\"TcpSocketEventInit\":[],\"Text\":[\"CharacterData\",\"EventTarget\",\"Node\"],\"TextDecodeOptions\":[],\"TextDecoder\":[],\"TextDecoderOptions\":[],\"TextEncoder\":[],\"TextMetrics\":[],\"TextTrack\":[\"EventTarget\"],\"TextTrackCue\":[\"EventTarget\"],\"TextTrackCueList\":[],\"TextTrackKind\":[],\"TextTrackList\":[\"EventTarget\"],\"TextTrackMode\":[],\"TimeEvent\":[\"Event\"],\"TimeRanges\":[],\"ToggleEvent\":[\"Event\"],\"ToggleEventInit\":[],\"TokenBinding\":[],\"TokenBindingStatus\":[],\"Touch\":[],\"TouchEvent\":[\"Event\",\"UiEvent\"],\"TouchEventInit\":[],\"TouchInit\":[],\"TouchList\":[],\"TrackEvent\":[\"Event\"],\"TrackEventInit\":[],\"TransformStream\":[],\"TransformStreamDefaultController\":[],\"Transformer\":[],\"TransitionEvent\":[\"Event\"],\"TransitionEventInit\":[],\"Transport\":[],\"TreeBoxObject\":[],\"TreeCellInfo\":[],\"TreeView\":[],\"TreeWalker\":[],\"U2f\":[],\"U2fClientData\":[],\"ULongRange\":[],\"UaDataValues\":[],\"UaLowEntropyJson\":[],\"UdpMessageEventInit\":[],\"UdpOptions\":[],\"UiEvent\":[\"Event\"],\"UiEventInit\":[],\"UnderlyingSink\":[],\"UnderlyingSource\":[],\"Url\":[],\"UrlSearchParams\":[],\"Usb\":[\"EventTarget\"],\"UsbAlternateInterface\":[],\"UsbConfiguration\":[],\"UsbConnectionEvent\":[\"Event\"],\"UsbConnectionEventInit\":[],\"UsbControlTransferParameters\":[],\"UsbDevice\":[],\"UsbDeviceFilter\":[],\"UsbDeviceRequestOptions\":[],\"UsbDirection\":[],\"UsbEndpoint\":[],\"UsbEndpointType\":[],\"UsbInTransferResult\":[],\"UsbInterface\":[],\"UsbIsochronousInTransferPacket\":[],\"UsbIsochronousInTransferResult\":[],\"UsbIsochronousOutTransferPacket\":[],\"UsbIsochronousOutTransferResult\":[],\"UsbOutTransferResult\":[],\"UsbPermissionDescriptor\":[],\"UsbPermissionResult\":[\"EventTarget\",\"PermissionStatus\"],\"UsbPermissionStorage\":[],\"UsbRecipient\":[],\"UsbRequestType\":[],\"UsbTransferStatus\":[],\"UserActivation\":[],\"UserProximityEvent\":[\"Event\"],\"UserProximityEventInit\":[],\"UserVerificationRequirement\":[],\"ValidityState\":[],\"ValueEvent\":[\"Event\"],\"ValueEventInit\":[],\"VideoColorPrimaries\":[],\"VideoColorSpace\":[],\"VideoColorSpaceInit\":[],\"VideoConfiguration\":[],\"VideoDecoder\":[],\"VideoDecoderConfig\":[],\"VideoDecoderInit\":[],\"VideoDecoderSupport\":[],\"VideoEncoder\":[],\"VideoEncoderConfig\":[],\"VideoEncoderEncodeOptions\":[],\"VideoEncoderInit\":[],\"VideoEncoderSupport\":[],\"VideoFacingModeEnum\":[],\"VideoFrame\":[],\"VideoFrameBufferInit\":[],\"VideoFrameCopyToOptions\":[],\"VideoFrameInit\":[],\"VideoMatrixCoefficients\":[],\"VideoPixelFormat\":[],\"VideoPlaybackQuality\":[],\"VideoStreamTrack\":[\"EventTarget\",\"MediaStreamTrack\"],\"VideoTrack\":[],\"VideoTrackList\":[\"EventTarget\"],\"VideoTransferCharacteristics\":[],\"ViewTransition\":[],\"VisibilityState\":[],\"VisualViewport\":[\"EventTarget\"],\"VoidCallback\":[],\"VrDisplay\":[\"EventTarget\"],\"VrDisplayCapabilities\":[],\"VrEye\":[],\"VrEyeParameters\":[],\"VrFieldOfView\":[],\"VrFrameData\":[],\"VrLayer\":[],\"VrMockController\":[],\"VrMockDisplay\":[],\"VrPose\":[],\"VrServiceTest\":[],\"VrStageParameters\":[],\"VrSubmitFrameResult\":[],\"VttCue\":[\"EventTarget\",\"TextTrackCue\"],\"VttRegion\":[],\"WakeLock\":[],\"WakeLockSentinel\":[\"EventTarget\"],\"WakeLockType\":[],\"WatchAdvertisementsOptions\":[],\"WaveShaperNode\":[\"AudioNode\",\"EventTarget\"],\"WaveShaperOptions\":[],\"WebGl2RenderingContext\":[],\"WebGlActiveInfo\":[],\"WebGlBuffer\":[],\"WebGlContextAttributes\":[],\"WebGlContextEvent\":[\"Event\"],\"WebGlContextEventInit\":[],\"WebGlFramebuffer\":[],\"WebGlPowerPreference\":[],\"WebGlProgram\":[],\"WebGlQuery\":[],\"WebGlRenderbuffer\":[],\"WebGlRenderingContext\":[],\"WebGlSampler\":[],\"WebGlShader\":[],\"WebGlShaderPrecisionFormat\":[],\"WebGlSync\":[],\"WebGlTexture\":[],\"WebGlTransformFeedback\":[],\"WebGlUniformLocation\":[],\"WebGlVertexArrayObject\":[],\"WebKitCssMatrix\":[\"DomMatrix\",\"DomMatrixReadOnly\"],\"WebSocket\":[\"EventTarget\"],\"WebSocketDict\":[],\"WebSocketElement\":[],\"WebTransport\":[],\"WebTransportBidirectionalStream\":[],\"WebTransportCloseInfo\":[],\"WebTransportCongestionControl\":[],\"WebTransportDatagramDuplexStream\":[],\"WebTransportDatagramStats\":[],\"WebTransportError\":[\"DomException\"],\"WebTransportErrorOptions\":[],\"WebTransportErrorSource\":[],\"WebTransportHash\":[],\"WebTransportOptions\":[],\"WebTransportReceiveStream\":[\"ReadableStream\"],\"WebTransportReceiveStreamStats\":[],\"WebTransportReliabilityMode\":[],\"WebTransportSendStream\":[\"WritableStream\"],\"WebTransportSendStreamOptions\":[],\"WebTransportSendStreamStats\":[],\"WebTransportStats\":[],\"WebglColorBufferFloat\":[],\"WebglCompressedTextureAstc\":[],\"WebglCompressedTextureAtc\":[],\"WebglCompressedTextureEtc\":[],\"WebglCompressedTextureEtc1\":[],\"WebglCompressedTexturePvrtc\":[],\"WebglCompressedTextureS3tc\":[],\"WebglCompressedTextureS3tcSrgb\":[],\"WebglDebugRendererInfo\":[],\"WebglDebugShaders\":[],\"WebglDepthTexture\":[],\"WebglDrawBuffers\":[],\"WebglLoseContext\":[],\"WebglMultiDraw\":[],\"WellKnownDirectory\":[],\"WgslLanguageFeatures\":[],\"WheelEvent\":[\"Event\",\"MouseEvent\",\"UiEvent\"],\"WheelEventInit\":[],\"WidevineCdmManifest\":[],\"Window\":[\"EventTarget\"],\"WindowClient\":[\"Client\"],\"Worker\":[\"EventTarget\"],\"WorkerDebuggerGlobalScope\":[\"EventTarget\"],\"WorkerGlobalScope\":[\"EventTarget\"],\"WorkerLocation\":[],\"WorkerNavigator\":[],\"WorkerOptions\":[],\"WorkerType\":[],\"Worklet\":[],\"WorkletGlobalScope\":[],\"WorkletOptions\":[],\"WritableStream\":[],\"WritableStreamDefaultController\":[],\"WritableStreamDefaultWriter\":[],\"WriteCommandType\":[],\"WriteParams\":[],\"XPathExpression\":[],\"XPathNsResolver\":[],\"XPathResult\":[],\"XmlDocument\":[\"Document\",\"EventTarget\",\"Node\"],\"XmlHttpRequest\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlHttpRequestEventTarget\":[\"EventTarget\"],\"XmlHttpRequestResponseType\":[],\"XmlHttpRequestUpload\":[\"EventTarget\",\"XmlHttpRequestEventTarget\"],\"XmlSerializer\":[],\"XrBoundedReferenceSpace\":[\"EventTarget\",\"XrReferenceSpace\",\"XrSpace\"],\"XrEye\":[],\"XrFrame\":[],\"XrHand\":[],\"XrHandJoint\":[],\"XrHandedness\":[],\"XrInputSource\":[],\"XrInputSourceArray\":[],\"XrInputSourceEvent\":[\"Event\"],\"XrInputSourceEventInit\":[],\"XrInputSourcesChangeEvent\":[\"Event\"],\"XrInputSourcesChangeEventInit\":[],\"XrJointPose\":[\"XrPose\"],\"XrJointSpace\":[\"EventTarget\",\"XrSpace\"],\"XrLayer\":[\"EventTarget\"],\"XrPermissionDescriptor\":[],\"XrPermissionStatus\":[\"EventTarget\",\"PermissionStatus\"],\"XrPose\":[],\"XrReferenceSpace\":[\"EventTarget\",\"XrSpace\"],\"XrReferenceSpaceEvent\":[\"Event\"],\"XrReferenceSpaceEventInit\":[],\"XrReferenceSpaceType\":[],\"XrRenderState\":[],\"XrRenderStateInit\":[],\"XrRigidTransform\":[],\"XrSession\":[\"EventTarget\"],\"XrSessionEvent\":[\"Event\"],\"XrSessionEventInit\":[],\"XrSessionInit\":[],\"XrSessionMode\":[],\"XrSessionSupportedPermissionDescriptor\":[],\"XrSpace\":[\"EventTarget\"],\"XrSystem\":[\"EventTarget\"],\"XrTargetRayMode\":[],\"XrView\":[],\"XrViewerPose\":[\"XrPose\"],\"XrViewport\":[],\"XrVisibilityState\":[],\"XrWebGlLayer\":[\"EventTarget\",\"XrLayer\"],\"XrWebGlLayerInit\":[],\"XsltProcessor\":[],\"console\":[],\"css\":[],\"default\":[\"std\"],\"gpu_buffer_usage\":[],\"gpu_color_write\":[],\"gpu_map_mode\":[],\"gpu_shader_stage\":[],\"gpu_texture_usage\":[],\"std\":[\"wasm-bindgen/std\",\"js-sys/std\"]}}", + "webpki-roots_0.26.11": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"parent\",\"package\":\"webpki-roots\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"ring\",\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.102\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.17.0\"},{\"kind\":\"dev\",\"name\":\"yasna\",\"req\":\"^0.5.2\"}],\"features\":{}}", + "webpki-roots_1.0.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"aws-lc-rs\",\"req\":\"^1.15.2\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"percent-encoding\",\"req\":\"^2.3\"},{\"default_features\":false,\"name\":\"pki-types\",\"package\":\"rustls-pki-types\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"rcgen\",\"req\":\"^0.14.3\"},{\"kind\":\"dev\",\"name\":\"rustls\",\"req\":\"^0.23\"},{\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"webpki\",\"package\":\"rustls-webpki\",\"req\":\"^0.103\"},{\"kind\":\"dev\",\"name\":\"x509-parser\",\"req\":\"^0.18\"},{\"kind\":\"dev\",\"name\":\"yasna\",\"req\":\"^0.6\"}],\"features\":{}}", + "winapi-util_0.1.11": "{\"dependencies\":[{\"features\":[\"Win32_Foundation\",\"Win32_Storage_FileSystem\",\"Win32_System_Console\",\"Win32_System_SystemInformation\"],\"name\":\"windows-sys\",\"req\":\">=0.48.0, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{}}", + "windows-core_0.62.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"windows-implement\",\"req\":\"^0.60.2\"},{\"default_features\":false,\"name\":\"windows-interface\",\"req\":\"^0.59.3\"},{\"default_features\":false,\"name\":\"windows-link\",\"req\":\"^0.2.1\"},{\"default_features\":false,\"name\":\"windows-result\",\"req\":\"^0.4.1\"},{\"default_features\":false,\"name\":\"windows-strings\",\"req\":\"^0.5.1\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"windows-result/std\",\"windows-strings/std\"]}}", + "windows-implement_0.60.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"parsing\",\"proc-macro\",\"printing\",\"full\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{}}", + "windows-interface_0.59.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"parsing\",\"proc-macro\",\"printing\",\"full\",\"clone-impls\"],\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{}}", + "windows-link_0.2.1": "{\"dependencies\":[],\"features\":{}}", + "windows-result_0.4.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"windows-link\",\"req\":\"^0.2.1\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "windows-strings_0.5.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"windows-link\",\"req\":\"^0.2.1\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", + "windows-sys_0.52.0": "{\"dependencies\":[{\"name\":\"windows-targets\",\"req\":\"^0.52.0\"}],\"features\":{\"Wdk\":[],\"Wdk_Foundation\":[\"Wdk\"],\"Wdk_Graphics\":[\"Wdk\"],\"Wdk_Graphics_Direct3D\":[\"Wdk_Graphics\"],\"Wdk_Storage\":[\"Wdk\"],\"Wdk_Storage_FileSystem\":[\"Wdk_Storage\"],\"Wdk_Storage_FileSystem_Minifilters\":[\"Wdk_Storage_FileSystem\"],\"Wdk_System\":[\"Wdk\"],\"Wdk_System_IO\":[\"Wdk_System\"],\"Wdk_System_OfflineRegistry\":[\"Wdk_System\"],\"Wdk_System_Registry\":[\"Wdk_System\"],\"Wdk_System_SystemInformation\":[\"Wdk_System\"],\"Wdk_System_SystemServices\":[\"Wdk_System\"],\"Wdk_System_Threading\":[\"Wdk_System\"],\"Win32\":[],\"Win32_Data\":[\"Win32\"],\"Win32_Data_HtmlHelp\":[\"Win32_Data\"],\"Win32_Data_RightsManagement\":[\"Win32_Data\"],\"Win32_Devices\":[\"Win32\"],\"Win32_Devices_AllJoyn\":[\"Win32_Devices\"],\"Win32_Devices_BiometricFramework\":[\"Win32_Devices\"],\"Win32_Devices_Bluetooth\":[\"Win32_Devices\"],\"Win32_Devices_Communication\":[\"Win32_Devices\"],\"Win32_Devices_DeviceAndDriverInstallation\":[\"Win32_Devices\"],\"Win32_Devices_DeviceQuery\":[\"Win32_Devices\"],\"Win32_Devices_Display\":[\"Win32_Devices\"],\"Win32_Devices_Enumeration\":[\"Win32_Devices\"],\"Win32_Devices_Enumeration_Pnp\":[\"Win32_Devices_Enumeration\"],\"Win32_Devices_Fax\":[\"Win32_Devices\"],\"Win32_Devices_HumanInterfaceDevice\":[\"Win32_Devices\"],\"Win32_Devices_PortableDevices\":[\"Win32_Devices\"],\"Win32_Devices_Properties\":[\"Win32_Devices\"],\"Win32_Devices_Pwm\":[\"Win32_Devices\"],\"Win32_Devices_Sensors\":[\"Win32_Devices\"],\"Win32_Devices_SerialCommunication\":[\"Win32_Devices\"],\"Win32_Devices_Tapi\":[\"Win32_Devices\"],\"Win32_Devices_Usb\":[\"Win32_Devices\"],\"Win32_Devices_WebServicesOnDevices\":[\"Win32_Devices\"],\"Win32_Foundation\":[\"Win32\"],\"Win32_Gaming\":[\"Win32\"],\"Win32_Globalization\":[\"Win32\"],\"Win32_Graphics\":[\"Win32\"],\"Win32_Graphics_Dwm\":[\"Win32_Graphics\"],\"Win32_Graphics_Gdi\":[\"Win32_Graphics\"],\"Win32_Graphics_GdiPlus\":[\"Win32_Graphics\"],\"Win32_Graphics_Hlsl\":[\"Win32_Graphics\"],\"Win32_Graphics_OpenGL\":[\"Win32_Graphics\"],\"Win32_Graphics_Printing\":[\"Win32_Graphics\"],\"Win32_Graphics_Printing_PrintTicket\":[\"Win32_Graphics_Printing\"],\"Win32_Management\":[\"Win32\"],\"Win32_Management_MobileDeviceManagementRegistration\":[\"Win32_Management\"],\"Win32_Media\":[\"Win32\"],\"Win32_Media_Audio\":[\"Win32_Media\"],\"Win32_Media_DxMediaObjects\":[\"Win32_Media\"],\"Win32_Media_KernelStreaming\":[\"Win32_Media\"],\"Win32_Media_Multimedia\":[\"Win32_Media\"],\"Win32_Media_Streaming\":[\"Win32_Media\"],\"Win32_Media_WindowsMediaFormat\":[\"Win32_Media\"],\"Win32_NetworkManagement\":[\"Win32\"],\"Win32_NetworkManagement_Dhcp\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Dns\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_InternetConnectionWizard\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_IpHelper\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Multicast\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Ndis\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetBios\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetManagement\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetShell\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetworkDiagnosticsFramework\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_P2P\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_QoS\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Rras\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Snmp\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WNet\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WebDav\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WiFi\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsConnectionManager\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsFilteringPlatform\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsFirewall\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsNetworkVirtualization\":[\"Win32_NetworkManagement\"],\"Win32_Networking\":[\"Win32\"],\"Win32_Networking_ActiveDirectory\":[\"Win32_Networking\"],\"Win32_Networking_Clustering\":[\"Win32_Networking\"],\"Win32_Networking_HttpServer\":[\"Win32_Networking\"],\"Win32_Networking_Ldap\":[\"Win32_Networking\"],\"Win32_Networking_WebSocket\":[\"Win32_Networking\"],\"Win32_Networking_WinHttp\":[\"Win32_Networking\"],\"Win32_Networking_WinInet\":[\"Win32_Networking\"],\"Win32_Networking_WinSock\":[\"Win32_Networking\"],\"Win32_Networking_WindowsWebServices\":[\"Win32_Networking\"],\"Win32_Security\":[\"Win32\"],\"Win32_Security_AppLocker\":[\"Win32_Security\"],\"Win32_Security_Authentication\":[\"Win32_Security\"],\"Win32_Security_Authentication_Identity\":[\"Win32_Security_Authentication\"],\"Win32_Security_Authorization\":[\"Win32_Security\"],\"Win32_Security_Credentials\":[\"Win32_Security\"],\"Win32_Security_Cryptography\":[\"Win32_Security\"],\"Win32_Security_Cryptography_Catalog\":[\"Win32_Security_Cryptography\"],\"Win32_Security_Cryptography_Certificates\":[\"Win32_Security_Cryptography\"],\"Win32_Security_Cryptography_Sip\":[\"Win32_Security_Cryptography\"],\"Win32_Security_Cryptography_UI\":[\"Win32_Security_Cryptography\"],\"Win32_Security_DiagnosticDataQuery\":[\"Win32_Security\"],\"Win32_Security_DirectoryServices\":[\"Win32_Security\"],\"Win32_Security_EnterpriseData\":[\"Win32_Security\"],\"Win32_Security_ExtensibleAuthenticationProtocol\":[\"Win32_Security\"],\"Win32_Security_Isolation\":[\"Win32_Security\"],\"Win32_Security_LicenseProtection\":[\"Win32_Security\"],\"Win32_Security_NetworkAccessProtection\":[\"Win32_Security\"],\"Win32_Security_WinTrust\":[\"Win32_Security\"],\"Win32_Security_WinWlx\":[\"Win32_Security\"],\"Win32_Storage\":[\"Win32\"],\"Win32_Storage_Cabinets\":[\"Win32_Storage\"],\"Win32_Storage_CloudFilters\":[\"Win32_Storage\"],\"Win32_Storage_Compression\":[\"Win32_Storage\"],\"Win32_Storage_DistributedFileSystem\":[\"Win32_Storage\"],\"Win32_Storage_FileHistory\":[\"Win32_Storage\"],\"Win32_Storage_FileSystem\":[\"Win32_Storage\"],\"Win32_Storage_Imapi\":[\"Win32_Storage\"],\"Win32_Storage_IndexServer\":[\"Win32_Storage\"],\"Win32_Storage_InstallableFileSystems\":[\"Win32_Storage\"],\"Win32_Storage_IscsiDisc\":[\"Win32_Storage\"],\"Win32_Storage_Jet\":[\"Win32_Storage\"],\"Win32_Storage_Nvme\":[\"Win32_Storage\"],\"Win32_Storage_OfflineFiles\":[\"Win32_Storage\"],\"Win32_Storage_OperationRecorder\":[\"Win32_Storage\"],\"Win32_Storage_Packaging\":[\"Win32_Storage\"],\"Win32_Storage_Packaging_Appx\":[\"Win32_Storage_Packaging\"],\"Win32_Storage_ProjectedFileSystem\":[\"Win32_Storage\"],\"Win32_Storage_StructuredStorage\":[\"Win32_Storage\"],\"Win32_Storage_Vhd\":[\"Win32_Storage\"],\"Win32_Storage_Xps\":[\"Win32_Storage\"],\"Win32_System\":[\"Win32\"],\"Win32_System_AddressBook\":[\"Win32_System\"],\"Win32_System_Antimalware\":[\"Win32_System\"],\"Win32_System_ApplicationInstallationAndServicing\":[\"Win32_System\"],\"Win32_System_ApplicationVerifier\":[\"Win32_System\"],\"Win32_System_ClrHosting\":[\"Win32_System\"],\"Win32_System_Com\":[\"Win32_System\"],\"Win32_System_Com_Marshal\":[\"Win32_System_Com\"],\"Win32_System_Com_StructuredStorage\":[\"Win32_System_Com\"],\"Win32_System_Com_Urlmon\":[\"Win32_System_Com\"],\"Win32_System_ComponentServices\":[\"Win32_System\"],\"Win32_System_Console\":[\"Win32_System\"],\"Win32_System_CorrelationVector\":[\"Win32_System\"],\"Win32_System_DataExchange\":[\"Win32_System\"],\"Win32_System_DeploymentServices\":[\"Win32_System\"],\"Win32_System_DeveloperLicensing\":[\"Win32_System\"],\"Win32_System_Diagnostics\":[\"Win32_System\"],\"Win32_System_Diagnostics_Ceip\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_Debug\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_Debug_Extensions\":[\"Win32_System_Diagnostics_Debug\"],\"Win32_System_Diagnostics_Etw\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_ProcessSnapshotting\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_ToolHelp\":[\"Win32_System_Diagnostics\"],\"Win32_System_DistributedTransactionCoordinator\":[\"Win32_System\"],\"Win32_System_Environment\":[\"Win32_System\"],\"Win32_System_ErrorReporting\":[\"Win32_System\"],\"Win32_System_EventCollector\":[\"Win32_System\"],\"Win32_System_EventLog\":[\"Win32_System\"],\"Win32_System_EventNotificationService\":[\"Win32_System\"],\"Win32_System_GroupPolicy\":[\"Win32_System\"],\"Win32_System_HostCompute\":[\"Win32_System\"],\"Win32_System_HostComputeNetwork\":[\"Win32_System\"],\"Win32_System_HostComputeSystem\":[\"Win32_System\"],\"Win32_System_Hypervisor\":[\"Win32_System\"],\"Win32_System_IO\":[\"Win32_System\"],\"Win32_System_Iis\":[\"Win32_System\"],\"Win32_System_Ioctl\":[\"Win32_System\"],\"Win32_System_JobObjects\":[\"Win32_System\"],\"Win32_System_Js\":[\"Win32_System\"],\"Win32_System_Kernel\":[\"Win32_System\"],\"Win32_System_LibraryLoader\":[\"Win32_System\"],\"Win32_System_Mailslots\":[\"Win32_System\"],\"Win32_System_Mapi\":[\"Win32_System\"],\"Win32_System_Memory\":[\"Win32_System\"],\"Win32_System_Memory_NonVolatile\":[\"Win32_System_Memory\"],\"Win32_System_MessageQueuing\":[\"Win32_System\"],\"Win32_System_MixedReality\":[\"Win32_System\"],\"Win32_System_Ole\":[\"Win32_System\"],\"Win32_System_PasswordManagement\":[\"Win32_System\"],\"Win32_System_Performance\":[\"Win32_System\"],\"Win32_System_Performance_HardwareCounterProfiling\":[\"Win32_System_Performance\"],\"Win32_System_Pipes\":[\"Win32_System\"],\"Win32_System_Power\":[\"Win32_System\"],\"Win32_System_ProcessStatus\":[\"Win32_System\"],\"Win32_System_Recovery\":[\"Win32_System\"],\"Win32_System_Registry\":[\"Win32_System\"],\"Win32_System_RemoteDesktop\":[\"Win32_System\"],\"Win32_System_RemoteManagement\":[\"Win32_System\"],\"Win32_System_RestartManager\":[\"Win32_System\"],\"Win32_System_Restore\":[\"Win32_System\"],\"Win32_System_Rpc\":[\"Win32_System\"],\"Win32_System_Search\":[\"Win32_System\"],\"Win32_System_Search_Common\":[\"Win32_System_Search\"],\"Win32_System_SecurityCenter\":[\"Win32_System\"],\"Win32_System_Services\":[\"Win32_System\"],\"Win32_System_SetupAndMigration\":[\"Win32_System\"],\"Win32_System_Shutdown\":[\"Win32_System\"],\"Win32_System_StationsAndDesktops\":[\"Win32_System\"],\"Win32_System_SubsystemForLinux\":[\"Win32_System\"],\"Win32_System_SystemInformation\":[\"Win32_System\"],\"Win32_System_SystemServices\":[\"Win32_System\"],\"Win32_System_Threading\":[\"Win32_System\"],\"Win32_System_Time\":[\"Win32_System\"],\"Win32_System_TpmBaseServices\":[\"Win32_System\"],\"Win32_System_UserAccessLogging\":[\"Win32_System\"],\"Win32_System_Variant\":[\"Win32_System\"],\"Win32_System_VirtualDosMachines\":[\"Win32_System\"],\"Win32_System_WindowsProgramming\":[\"Win32_System\"],\"Win32_System_Wmi\":[\"Win32_System\"],\"Win32_UI\":[\"Win32\"],\"Win32_UI_Accessibility\":[\"Win32_UI\"],\"Win32_UI_ColorSystem\":[\"Win32_UI\"],\"Win32_UI_Controls\":[\"Win32_UI\"],\"Win32_UI_Controls_Dialogs\":[\"Win32_UI_Controls\"],\"Win32_UI_HiDpi\":[\"Win32_UI\"],\"Win32_UI_Input\":[\"Win32_UI\"],\"Win32_UI_Input_Ime\":[\"Win32_UI_Input\"],\"Win32_UI_Input_KeyboardAndMouse\":[\"Win32_UI_Input\"],\"Win32_UI_Input_Pointer\":[\"Win32_UI_Input\"],\"Win32_UI_Input_Touch\":[\"Win32_UI_Input\"],\"Win32_UI_Input_XboxController\":[\"Win32_UI_Input\"],\"Win32_UI_InteractionContext\":[\"Win32_UI\"],\"Win32_UI_Magnification\":[\"Win32_UI\"],\"Win32_UI_Shell\":[\"Win32_UI\"],\"Win32_UI_Shell_PropertiesSystem\":[\"Win32_UI_Shell\"],\"Win32_UI_TabletPC\":[\"Win32_UI\"],\"Win32_UI_TextServices\":[\"Win32_UI\"],\"Win32_UI_WindowsAndMessaging\":[\"Win32_UI\"],\"Win32_Web\":[\"Win32\"],\"Win32_Web_InternetExplorer\":[\"Win32_Web\"],\"default\":[],\"docs\":[]}}", + "windows-sys_0.61.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"windows-link\",\"req\":\"^0.2.1\"}],\"features\":{\"Wdk\":[\"Win32_Foundation\"],\"Wdk_Devices\":[\"Wdk\"],\"Wdk_Devices_Bluetooth\":[\"Wdk_Devices\"],\"Wdk_Devices_HumanInterfaceDevice\":[\"Wdk_Devices\"],\"Wdk_Foundation\":[\"Wdk\"],\"Wdk_Graphics\":[\"Wdk\"],\"Wdk_Graphics_Direct3D\":[\"Wdk_Graphics\"],\"Wdk_NetworkManagement\":[\"Wdk\"],\"Wdk_NetworkManagement_Ndis\":[\"Wdk_NetworkManagement\"],\"Wdk_NetworkManagement_WindowsFilteringPlatform\":[\"Wdk_NetworkManagement\"],\"Wdk_Storage\":[\"Wdk\"],\"Wdk_Storage_FileSystem\":[\"Wdk_Storage\"],\"Wdk_Storage_FileSystem_Minifilters\":[\"Wdk_Storage_FileSystem\"],\"Wdk_System\":[\"Wdk\"],\"Wdk_System_IO\":[\"Wdk_System\"],\"Wdk_System_Memory\":[\"Wdk_System\"],\"Wdk_System_OfflineRegistry\":[\"Wdk_System\"],\"Wdk_System_Registry\":[\"Wdk_System\"],\"Wdk_System_SystemInformation\":[\"Wdk_System\"],\"Wdk_System_SystemServices\":[\"Wdk_System\"],\"Wdk_System_Threading\":[\"Wdk_System\"],\"Win32\":[\"Win32_Foundation\"],\"Win32_Data\":[\"Win32\"],\"Win32_Data_HtmlHelp\":[\"Win32_Data\"],\"Win32_Data_RightsManagement\":[\"Win32_Data\"],\"Win32_Devices\":[\"Win32\"],\"Win32_Devices_AllJoyn\":[\"Win32_Devices\"],\"Win32_Devices_Beep\":[\"Win32_Devices\"],\"Win32_Devices_BiometricFramework\":[\"Win32_Devices\"],\"Win32_Devices_Bluetooth\":[\"Win32_Devices\"],\"Win32_Devices_Cdrom\":[\"Win32_Devices\"],\"Win32_Devices_Communication\":[\"Win32_Devices\"],\"Win32_Devices_DeviceAndDriverInstallation\":[\"Win32_Devices\"],\"Win32_Devices_DeviceQuery\":[\"Win32_Devices\"],\"Win32_Devices_Display\":[\"Win32_Devices\"],\"Win32_Devices_Dvd\":[\"Win32_Devices\"],\"Win32_Devices_Enumeration\":[\"Win32_Devices\"],\"Win32_Devices_Enumeration_Pnp\":[\"Win32_Devices_Enumeration\"],\"Win32_Devices_Fax\":[\"Win32_Devices\"],\"Win32_Devices_HumanInterfaceDevice\":[\"Win32_Devices\"],\"Win32_Devices_Nfc\":[\"Win32_Devices\"],\"Win32_Devices_Nfp\":[\"Win32_Devices\"],\"Win32_Devices_PortableDevices\":[\"Win32_Devices\"],\"Win32_Devices_Properties\":[\"Win32_Devices\"],\"Win32_Devices_Pwm\":[\"Win32_Devices\"],\"Win32_Devices_Sensors\":[\"Win32_Devices\"],\"Win32_Devices_SerialCommunication\":[\"Win32_Devices\"],\"Win32_Devices_Tapi\":[\"Win32_Devices\"],\"Win32_Devices_Usb\":[\"Win32_Devices\"],\"Win32_Devices_WebServicesOnDevices\":[\"Win32_Devices\"],\"Win32_Foundation\":[\"Win32\"],\"Win32_Gaming\":[\"Win32\"],\"Win32_Globalization\":[\"Win32\"],\"Win32_Graphics\":[\"Win32\"],\"Win32_Graphics_Dwm\":[\"Win32_Graphics\"],\"Win32_Graphics_Gdi\":[\"Win32_Graphics\"],\"Win32_Graphics_GdiPlus\":[\"Win32_Graphics\"],\"Win32_Graphics_Hlsl\":[\"Win32_Graphics\"],\"Win32_Graphics_OpenGL\":[\"Win32_Graphics\"],\"Win32_Graphics_Printing\":[\"Win32_Graphics\"],\"Win32_Graphics_Printing_PrintTicket\":[\"Win32_Graphics_Printing\"],\"Win32_Management\":[\"Win32\"],\"Win32_Management_MobileDeviceManagementRegistration\":[\"Win32_Management\"],\"Win32_Media\":[\"Win32\"],\"Win32_Media_Audio\":[\"Win32_Media\"],\"Win32_Media_DxMediaObjects\":[\"Win32_Media\"],\"Win32_Media_KernelStreaming\":[\"Win32_Media\"],\"Win32_Media_Multimedia\":[\"Win32_Media\"],\"Win32_Media_Streaming\":[\"Win32_Media\"],\"Win32_Media_WindowsMediaFormat\":[\"Win32_Media\"],\"Win32_NetworkManagement\":[\"Win32\"],\"Win32_NetworkManagement_Dhcp\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Dns\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_InternetConnectionWizard\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_IpHelper\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Multicast\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Ndis\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetBios\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetManagement\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetShell\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_NetworkDiagnosticsFramework\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_P2P\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_QoS\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Rras\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_Snmp\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WNet\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WebDav\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WiFi\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsConnectionManager\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsFilteringPlatform\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsFirewall\":[\"Win32_NetworkManagement\"],\"Win32_NetworkManagement_WindowsNetworkVirtualization\":[\"Win32_NetworkManagement\"],\"Win32_Networking\":[\"Win32\"],\"Win32_Networking_ActiveDirectory\":[\"Win32_Networking\"],\"Win32_Networking_Clustering\":[\"Win32_Networking\"],\"Win32_Networking_HttpServer\":[\"Win32_Networking\"],\"Win32_Networking_Ldap\":[\"Win32_Networking\"],\"Win32_Networking_WebSocket\":[\"Win32_Networking\"],\"Win32_Networking_WinHttp\":[\"Win32_Networking\"],\"Win32_Networking_WinInet\":[\"Win32_Networking\"],\"Win32_Networking_WinSock\":[\"Win32_Networking\"],\"Win32_Networking_WindowsWebServices\":[\"Win32_Networking\"],\"Win32_Security\":[\"Win32\"],\"Win32_Security_AppLocker\":[\"Win32_Security\"],\"Win32_Security_Authentication\":[\"Win32_Security\"],\"Win32_Security_Authentication_Identity\":[\"Win32_Security_Authentication\"],\"Win32_Security_Authorization\":[\"Win32_Security\"],\"Win32_Security_Credentials\":[\"Win32_Security\"],\"Win32_Security_Cryptography\":[\"Win32_Security\"],\"Win32_Security_Cryptography_Catalog\":[\"Win32_Security_Cryptography\"],\"Win32_Security_Cryptography_Certificates\":[\"Win32_Security_Cryptography\"],\"Win32_Security_Cryptography_Sip\":[\"Win32_Security_Cryptography\"],\"Win32_Security_Cryptography_UI\":[\"Win32_Security_Cryptography\"],\"Win32_Security_DiagnosticDataQuery\":[\"Win32_Security\"],\"Win32_Security_DirectoryServices\":[\"Win32_Security\"],\"Win32_Security_EnterpriseData\":[\"Win32_Security\"],\"Win32_Security_ExtensibleAuthenticationProtocol\":[\"Win32_Security\"],\"Win32_Security_Isolation\":[\"Win32_Security\"],\"Win32_Security_LicenseProtection\":[\"Win32_Security\"],\"Win32_Security_NetworkAccessProtection\":[\"Win32_Security\"],\"Win32_Security_WinTrust\":[\"Win32_Security\"],\"Win32_Security_WinWlx\":[\"Win32_Security\"],\"Win32_Storage\":[\"Win32\"],\"Win32_Storage_Cabinets\":[\"Win32_Storage\"],\"Win32_Storage_CloudFilters\":[\"Win32_Storage\"],\"Win32_Storage_Compression\":[\"Win32_Storage\"],\"Win32_Storage_DistributedFileSystem\":[\"Win32_Storage\"],\"Win32_Storage_FileHistory\":[\"Win32_Storage\"],\"Win32_Storage_FileSystem\":[\"Win32_Storage\"],\"Win32_Storage_Imapi\":[\"Win32_Storage\"],\"Win32_Storage_IndexServer\":[\"Win32_Storage\"],\"Win32_Storage_InstallableFileSystems\":[\"Win32_Storage\"],\"Win32_Storage_IscsiDisc\":[\"Win32_Storage\"],\"Win32_Storage_Jet\":[\"Win32_Storage\"],\"Win32_Storage_Nvme\":[\"Win32_Storage\"],\"Win32_Storage_OfflineFiles\":[\"Win32_Storage\"],\"Win32_Storage_OperationRecorder\":[\"Win32_Storage\"],\"Win32_Storage_Packaging\":[\"Win32_Storage\"],\"Win32_Storage_Packaging_Appx\":[\"Win32_Storage_Packaging\"],\"Win32_Storage_ProjectedFileSystem\":[\"Win32_Storage\"],\"Win32_Storage_StructuredStorage\":[\"Win32_Storage\"],\"Win32_Storage_Vhd\":[\"Win32_Storage\"],\"Win32_Storage_Xps\":[\"Win32_Storage\"],\"Win32_System\":[\"Win32\"],\"Win32_System_AddressBook\":[\"Win32_System\"],\"Win32_System_Antimalware\":[\"Win32_System\"],\"Win32_System_ApplicationInstallationAndServicing\":[\"Win32_System\"],\"Win32_System_ApplicationVerifier\":[\"Win32_System\"],\"Win32_System_ClrHosting\":[\"Win32_System\"],\"Win32_System_Com\":[\"Win32_System\"],\"Win32_System_Com_Marshal\":[\"Win32_System_Com\"],\"Win32_System_Com_StructuredStorage\":[\"Win32_System_Com\"],\"Win32_System_Com_Urlmon\":[\"Win32_System_Com\"],\"Win32_System_ComponentServices\":[\"Win32_System\"],\"Win32_System_Console\":[\"Win32_System\"],\"Win32_System_CorrelationVector\":[\"Win32_System\"],\"Win32_System_DataExchange\":[\"Win32_System\"],\"Win32_System_DeploymentServices\":[\"Win32_System\"],\"Win32_System_DeveloperLicensing\":[\"Win32_System\"],\"Win32_System_Diagnostics\":[\"Win32_System\"],\"Win32_System_Diagnostics_Ceip\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_Debug\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_Debug_Extensions\":[\"Win32_System_Diagnostics_Debug\"],\"Win32_System_Diagnostics_Etw\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_ProcessSnapshotting\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_ToolHelp\":[\"Win32_System_Diagnostics\"],\"Win32_System_Diagnostics_TraceLogging\":[\"Win32_System_Diagnostics\"],\"Win32_System_DistributedTransactionCoordinator\":[\"Win32_System\"],\"Win32_System_Environment\":[\"Win32_System\"],\"Win32_System_ErrorReporting\":[\"Win32_System\"],\"Win32_System_EventCollector\":[\"Win32_System\"],\"Win32_System_EventLog\":[\"Win32_System\"],\"Win32_System_EventNotificationService\":[\"Win32_System\"],\"Win32_System_GroupPolicy\":[\"Win32_System\"],\"Win32_System_HostCompute\":[\"Win32_System\"],\"Win32_System_HostComputeNetwork\":[\"Win32_System\"],\"Win32_System_HostComputeSystem\":[\"Win32_System\"],\"Win32_System_Hypervisor\":[\"Win32_System\"],\"Win32_System_IO\":[\"Win32_System\"],\"Win32_System_Iis\":[\"Win32_System\"],\"Win32_System_Ioctl\":[\"Win32_System\"],\"Win32_System_JobObjects\":[\"Win32_System\"],\"Win32_System_Js\":[\"Win32_System\"],\"Win32_System_Kernel\":[\"Win32_System\"],\"Win32_System_LibraryLoader\":[\"Win32_System\"],\"Win32_System_Mailslots\":[\"Win32_System\"],\"Win32_System_Mapi\":[\"Win32_System\"],\"Win32_System_Memory\":[\"Win32_System\"],\"Win32_System_Memory_NonVolatile\":[\"Win32_System_Memory\"],\"Win32_System_MessageQueuing\":[\"Win32_System\"],\"Win32_System_MixedReality\":[\"Win32_System\"],\"Win32_System_Ole\":[\"Win32_System\"],\"Win32_System_PasswordManagement\":[\"Win32_System\"],\"Win32_System_Performance\":[\"Win32_System\"],\"Win32_System_Performance_HardwareCounterProfiling\":[\"Win32_System_Performance\"],\"Win32_System_Pipes\":[\"Win32_System\"],\"Win32_System_Power\":[\"Win32_System\"],\"Win32_System_ProcessStatus\":[\"Win32_System\"],\"Win32_System_Recovery\":[\"Win32_System\"],\"Win32_System_Registry\":[\"Win32_System\"],\"Win32_System_RemoteDesktop\":[\"Win32_System\"],\"Win32_System_RemoteManagement\":[\"Win32_System\"],\"Win32_System_RestartManager\":[\"Win32_System\"],\"Win32_System_Restore\":[\"Win32_System\"],\"Win32_System_Rpc\":[\"Win32_System\"],\"Win32_System_Search\":[\"Win32_System\"],\"Win32_System_Search_Common\":[\"Win32_System_Search\"],\"Win32_System_SecurityCenter\":[\"Win32_System\"],\"Win32_System_Services\":[\"Win32_System\"],\"Win32_System_SetupAndMigration\":[\"Win32_System\"],\"Win32_System_Shutdown\":[\"Win32_System\"],\"Win32_System_StationsAndDesktops\":[\"Win32_System\"],\"Win32_System_SubsystemForLinux\":[\"Win32_System\"],\"Win32_System_SystemInformation\":[\"Win32_System\"],\"Win32_System_SystemServices\":[\"Win32_System\"],\"Win32_System_Threading\":[\"Win32_System\"],\"Win32_System_Time\":[\"Win32_System\"],\"Win32_System_TpmBaseServices\":[\"Win32_System\"],\"Win32_System_UserAccessLogging\":[\"Win32_System\"],\"Win32_System_Variant\":[\"Win32_System\"],\"Win32_System_VirtualDosMachines\":[\"Win32_System\"],\"Win32_System_WindowsProgramming\":[\"Win32_System\"],\"Win32_System_Wmi\":[\"Win32_System\"],\"Win32_UI\":[\"Win32\"],\"Win32_UI_Accessibility\":[\"Win32_UI\"],\"Win32_UI_ColorSystem\":[\"Win32_UI\"],\"Win32_UI_Controls\":[\"Win32_UI\"],\"Win32_UI_Controls_Dialogs\":[\"Win32_UI_Controls\"],\"Win32_UI_HiDpi\":[\"Win32_UI\"],\"Win32_UI_Input\":[\"Win32_UI\"],\"Win32_UI_Input_Ime\":[\"Win32_UI_Input\"],\"Win32_UI_Input_KeyboardAndMouse\":[\"Win32_UI_Input\"],\"Win32_UI_Input_Pointer\":[\"Win32_UI_Input\"],\"Win32_UI_Input_Touch\":[\"Win32_UI_Input\"],\"Win32_UI_Input_XboxController\":[\"Win32_UI_Input\"],\"Win32_UI_InteractionContext\":[\"Win32_UI\"],\"Win32_UI_Magnification\":[\"Win32_UI\"],\"Win32_UI_Shell\":[\"Win32_UI\"],\"Win32_UI_Shell_Common\":[\"Win32_UI_Shell\"],\"Win32_UI_Shell_PropertiesSystem\":[\"Win32_UI_Shell\"],\"Win32_UI_TabletPC\":[\"Win32_UI\"],\"Win32_UI_TextServices\":[\"Win32_UI\"],\"Win32_UI_WindowsAndMessaging\":[\"Win32_UI\"],\"Win32_Web\":[\"Win32\"],\"Win32_Web_InternetExplorer\":[\"Win32_Web\"],\"default\":[],\"docs\":[]}}", + "windows-targets_0.52.6": "{\"dependencies\":[{\"name\":\"windows_aarch64_gnullvm\",\"req\":\"^0.52.6\",\"target\":\"aarch64-pc-windows-gnullvm\"},{\"name\":\"windows_aarch64_msvc\",\"req\":\"^0.52.6\",\"target\":\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\"},{\"name\":\"windows_i686_gnu\",\"req\":\"^0.52.6\",\"target\":\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\"},{\"name\":\"windows_i686_gnullvm\",\"req\":\"^0.52.6\",\"target\":\"i686-pc-windows-gnullvm\"},{\"name\":\"windows_i686_msvc\",\"req\":\"^0.52.6\",\"target\":\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\"},{\"name\":\"windows_x86_64_gnu\",\"req\":\"^0.52.6\",\"target\":\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\"},{\"name\":\"windows_x86_64_gnullvm\",\"req\":\"^0.52.6\",\"target\":\"x86_64-pc-windows-gnullvm\"},{\"name\":\"windows_x86_64_msvc\",\"req\":\"^0.52.6\",\"target\":\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\"}],\"features\":{}}", + "windows_aarch64_gnullvm_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_aarch64_msvc_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_i686_gnu_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_i686_gnullvm_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_i686_msvc_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_x86_64_gnu_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_x86_64_gnullvm_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "windows_x86_64_msvc_0.52.6": "{\"dependencies\":[],\"features\":{}}", + "wit-bindgen-core_0.51.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.72\"},{\"features\":[\"derive\"],\"name\":\"clap\",\"optional\":true,\"req\":\"^4.3.19\"},{\"name\":\"heck\",\"req\":\"^0.5\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.218\"},{\"name\":\"wit-parser\",\"req\":\"^0.244.0\"}],\"features\":{\"clap\":[\"dep:clap\"],\"serde\":[\"dep:serde\"]}}", + "wit-bindgen-rust-macro_0.51.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.72\"},{\"name\":\"prettyplease\",\"req\":\"^0.2.20\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"features\":[\"printing\"],\"name\":\"syn\",\"req\":\"^2.0.89\"},{\"name\":\"wit-bindgen-core\",\"req\":\"^0.51.0\"},{\"name\":\"wit-bindgen-rust\",\"req\":\"^0.51.0\"}],\"features\":{\"async\":[]}}", + "wit-bindgen-rust_0.51.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.72\"},{\"kind\":\"dev\",\"name\":\"bytes\",\"req\":\"^1\"},{\"features\":[\"derive\"],\"name\":\"clap\",\"optional\":true,\"req\":\"^4.3.19\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.31\"},{\"name\":\"heck\",\"req\":\"^0.5\"},{\"name\":\"indexmap\",\"req\":\"^2.0.0\"},{\"name\":\"prettyplease\",\"req\":\"^0.2.20\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.218\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"features\":[\"printing\"],\"name\":\"syn\",\"req\":\"^2.0.89\"},{\"default_features\":false,\"name\":\"wasm-metadata\",\"req\":\"^0.244.0\"},{\"name\":\"wit-bindgen-core\",\"req\":\"^0.51.0\"},{\"name\":\"wit-component\",\"req\":\"^0.244.0\"}],\"features\":{\"clap\":[\"dep:clap\",\"wit-bindgen-core/clap\"],\"serde\":[\"dep:serde\",\"wit-bindgen-core/serde\"]}}", + "wit-bindgen_0.51.0": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0\"},{\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.3.3\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3.30\"},{\"name\":\"wit-bindgen-rust-macro\",\"optional\":true,\"req\":\"^0.51.0\"}],\"features\":{\"async\":[\"std\",\"wit-bindgen-rust-macro?/async\"],\"async-spawn\":[\"async\",\"dep:futures\"],\"bitflags\":[\"dep:bitflags\"],\"default\":[\"macros\",\"realloc\",\"async\",\"std\",\"bitflags\"],\"inter-task-wakeup\":[\"async\"],\"macros\":[\"dep:wit-bindgen-rust-macro\"],\"realloc\":[],\"rustc-dep-of-std\":[\"dep:core\",\"dep:alloc\"],\"std\":[]}}", + "wit-bindgen_0.57.1": "{\"dependencies\":[{\"name\":\"alloc\",\"optional\":true,\"package\":\"rustc-std-workspace-alloc\",\"req\":\"^1.0\"},{\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.11.1\"},{\"name\":\"core\",\"optional\":true,\"package\":\"rustc-std-workspace-core\",\"req\":\"^1.0\"},{\"name\":\"futures\",\"optional\":true,\"req\":\"^0.3.30\"},{\"default_features\":false,\"name\":\"wit-bindgen-rust-macro\",\"optional\":true,\"req\":\"^0.57.1\"}],\"features\":{\"async\":[],\"async-spawn\":[\"async\",\"dep:futures\",\"std\"],\"bitflags\":[\"dep:bitflags\"],\"default\":[\"macros\",\"realloc\",\"async\",\"std\",\"bitflags\",\"macro-string\"],\"futures-stream\":[\"async\",\"dep:futures\"],\"inter-task-wakeup\":[\"async\"],\"macro-string\":[\"wit-bindgen-rust-macro?/macro-string\"],\"macros\":[\"dep:wit-bindgen-rust-macro\"],\"realloc\":[],\"rustc-dep-of-std\":[\"dep:core\",\"dep:alloc\"],\"std\":[]}}", + "wit-component_0.244.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"name\":\"bitflags\",\"req\":\"^2.3.3\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3.0\"},{\"default_features\":false,\"name\":\"indexmap\",\"req\":\"^2.7.0\"},{\"kind\":\"dev\",\"name\":\"libtest-mimic\",\"req\":\"^0.8.1\"},{\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.3.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"req\":\"^1.0.166\"},{\"name\":\"serde_derive\",\"req\":\"^1.0.166\"},{\"name\":\"serde_json\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"std\",\"wasmparser\"],\"name\":\"wasm-encoder\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"name\":\"wasm-metadata\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"oci\"],\"kind\":\"dev\",\"name\":\"wasm-metadata\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"simd\",\"std\",\"component-model\",\"simd\"],\"name\":\"wasmparser\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"simd\",\"std\",\"component-model\",\"features\"],\"kind\":\"dev\",\"name\":\"wasmparser\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"component-model\"],\"kind\":\"dev\",\"name\":\"wasmprinter\",\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"cranelift\",\"component-model\",\"runtime\",\"gc-drc\"],\"kind\":\"dev\",\"name\":\"wasmtime\",\"req\":\"^34.0.1\",\"target\":\"cfg(not(target_family = \\\"wasm\\\"))\"},{\"default_features\":false,\"name\":\"wast\",\"optional\":true,\"req\":\"^244.0.0\"},{\"default_features\":false,\"name\":\"wat\",\"optional\":true,\"req\":\"^1.244.0\"},{\"default_features\":false,\"features\":[\"component-model\"],\"kind\":\"dev\",\"name\":\"wat\",\"req\":\"^1.244.0\"},{\"features\":[\"decoding\",\"serde\"],\"name\":\"wit-parser\",\"req\":\"^0.244.0\"}],\"features\":{\"dummy-module\":[\"dep:wat\"],\"semver-check\":[\"dummy-module\"],\"wat\":[\"dep:wast\",\"dep:wat\"]}}", + "wit-parser_0.244.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0.58\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"id-arena\",\"req\":\"^2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2.7.0\"},{\"kind\":\"dev\",\"name\":\"libtest-mimic\",\"req\":\"^0.8.1\"},{\"name\":\"log\",\"req\":\"^0.4.17\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1.3.0\"},{\"default_features\":false,\"name\":\"semver\",\"req\":\"^1.0.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.166\"},{\"name\":\"serde_derive\",\"optional\":true,\"req\":\"^1.0.166\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1\"},{\"name\":\"unicode-xid\",\"req\":\"^0.2.2\"},{\"default_features\":false,\"features\":[\"simd\",\"std\",\"validate\",\"component-model\",\"features\"],\"name\":\"wasmparser\",\"optional\":true,\"req\":\"^0.244.0\"},{\"default_features\":false,\"features\":[\"component-model\"],\"name\":\"wat\",\"optional\":true,\"req\":\"^1.244.0\"}],\"features\":{\"decoding\":[\"dep:wasmparser\"],\"default\":[\"serde\",\"decoding\"],\"serde\":[\"dep:serde\",\"dep:serde_derive\",\"indexmap/serde\",\"serde_json\"],\"wat\":[\"decoding\",\"dep:wat\"]}}", + "writeable_0.6.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"either\",\"optional\":true,\"req\":\"^1.9.0\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"],\"either\":[\"dep:either\"]}}", + "yoke-derive_0.8.2": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.61\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"features\":[\"fold\"],\"name\":\"syn\",\"req\":\"^2.0.21\"},{\"name\":\"synstructure\",\"req\":\"^0.13.0\"}],\"features\":{}}", + "yoke_0.8.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"stable_deref_trait\",\"req\":\"^1.2.0\"},{\"default_features\":false,\"name\":\"yoke-derive\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"zerofrom\",\"optional\":true,\"req\":\"^0.1.6\"}],\"features\":{\"alloc\":[\"stable_deref_trait/alloc\",\"zerofrom/alloc\"],\"default\":[\"alloc\",\"zerofrom\"],\"derive\":[\"dep:yoke-derive\",\"zerofrom/derive\"],\"serde\":[],\"zerofrom\":[\"dep:zerofrom\"]}}", + "zerocopy-derive_0.8.48": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"dissimilar\",\"req\":\"^1.0.9\"},{\"kind\":\"dev\",\"name\":\"prettyplease\",\"req\":\"=0.2.17\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.1\"},{\"name\":\"quote\",\"req\":\"^1.0.40\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.46\"},{\"features\":[\"visit\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.46\"}],\"features\":{}}", + "zerocopy_0.8.48": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"elain\",\"req\":\"^0.3.0\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.11\"},{\"default_features\":false,\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"},{\"name\":\"zerocopy-derive\",\"req\":\"=0.8.48\",\"target\":\"cfg(any())\"},{\"name\":\"zerocopy-derive\",\"optional\":true,\"req\":\"=0.8.48\"},{\"kind\":\"dev\",\"name\":\"zerocopy-derive\",\"req\":\"=0.8.48\"}],\"features\":{\"__internal_use_only_features_that_work_on_stable\":[\"alloc\",\"derive\",\"simd\",\"std\"],\"alloc\":[],\"derive\":[\"zerocopy-derive\"],\"float-nightly\":[],\"simd\":[],\"simd-nightly\":[\"simd\"],\"std\":[\"alloc\"]}}", + "zerofrom-derive_0.1.7": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0.61\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"features\":[\"fold\"],\"name\":\"syn\",\"req\":\"^2.0.21\"},{\"name\":\"synstructure\",\"req\":\"^0.13.0\"}],\"features\":{}}", + "zerofrom_0.1.8": "{\"dependencies\":[{\"default_features\":false,\"name\":\"zerofrom-derive\",\"optional\":true,\"req\":\"^0.1.6\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"],\"derive\":[\"dep:zerofrom-derive\"]}}", + "zeroize_1.8.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"zeroize_derive\",\"optional\":true,\"req\":\"^1.3\"}],\"features\":{\"aarch64\":[],\"alloc\":[],\"default\":[\"alloc\"],\"derive\":[\"zeroize_derive\"],\"simd\":[],\"std\":[\"alloc\"]}}", + "zerotrie_0.2.4": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"default_features\":false,\"name\":\"displaydoc\",\"req\":\"^0.2.3\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"icu_locale_core\",\"req\":\"^2.2.0\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"litemap\",\"optional\":true,\"req\":\"^0.8.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rmp-serde\",\"req\":\"^1.2.0\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"default_features\":false,\"name\":\"serde_core\",\"optional\":true,\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"zerofrom\",\"optional\":true,\"req\":\"^0.1.6\"},{\"default_features\":false,\"name\":\"zerovec\",\"optional\":true,\"req\":\"^0.11.6\"}],\"features\":{\"alloc\":[\"zerovec?/alloc\"],\"databake\":[\"dep:databake\",\"zerovec?/databake\"],\"default\":[],\"dense\":[\"dep:zerovec\"],\"litemap\":[\"dep:litemap\",\"alloc\"],\"serde\":[\"dep:serde_core\",\"dep:litemap\",\"alloc\",\"litemap/serde\",\"zerovec?/serde\"],\"yoke\":[\"dep:yoke\"],\"zerofrom\":[\"dep:zerofrom\"],\"zerovec\":[\"dep:zerovec\"]}}", + "zerovec-derive_0.11.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"name\":\"proc-macro2\",\"req\":\"^1.0.61\"},{\"name\":\"quote\",\"req\":\"^1.0.44\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"features\":[\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2.0.21\"}],\"features\":{}}", + "zerovec_0.11.6": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.1\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"databake\",\"optional\":true,\"req\":\"^0.2.0\"},{\"features\":[\"wasm_js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"iai\",\"req\":\"^0.1.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.43.2\"},{\"default_features\":false,\"features\":[\"use-std\"],\"kind\":\"dev\",\"name\":\"postcard\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rand_distr\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"rand_pcg\",\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rmp-serde\",\"req\":\"^1.2.0\"},{\"default_features\":false,\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0.4\"},{\"default_features\":false,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.220\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.220\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.45\"},{\"default_features\":false,\"features\":[\"xxhash64\"],\"name\":\"twox-hash\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"yoke\",\"optional\":true,\"req\":\"^0.8.2\"},{\"default_features\":false,\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"yoke\",\"req\":\"^0.8.2\"},{\"default_features\":false,\"name\":\"zerofrom\",\"req\":\"^0.1.6\"},{\"default_features\":false,\"name\":\"zerovec-derive\",\"optional\":true,\"req\":\"^0.11.3\"}],\"features\":{\"alloc\":[\"serde?/alloc\"],\"databake\":[\"dep:databake\"],\"derive\":[\"dep:zerovec-derive\"],\"hashmap\":[\"dep:twox-hash\",\"alloc\"],\"schemars\":[\"dep:schemars\",\"alloc\"],\"serde\":[\"dep:serde\"],\"std\":[],\"yoke\":[\"dep:yoke\"]}}", + "zmij_1.0.21": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8\",\"target\":\"cfg(not(miri))\"},{\"name\":\"no-panic\",\"optional\":true,\"req\":\"^0.1.36\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.8\"},{\"kind\":\"dev\",\"name\":\"opt-level\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"ryu\",\"req\":\"^1\"}],\"features\":{}}" + }, + "@@rules_rs+//rs/toolchains:module_extension.bzl%toolchains": { + "cargo-1.92.0-aarch64-apple-darwin.tar.xz": "bce6e7def37240c5a63115828017a9fc0ebcb31e64115382f5943b62b71aa34a", + "cargo-1.92.0-aarch64-pc-windows-msvc.tar.xz": "3fc47cc29781190c5075f807836c4b98d411aaf27c59598fbfb2aa781ccf6190", + "cargo-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "cb2ce6be6411b986e25c71ad8a813f9dfbe3461738136fd684e3644f8dd75df4", + "cargo-1.92.0-x86_64-apple-darwin.tar.xz": "b033a7c33aba8af947c9d0ab2785f9696347cded228ffe731897f1c627466262", + "cargo-1.92.0-x86_64-pc-windows-msvc.tar.xz": "f4057534ec58708ed3554957582a6c8e8c6abfee011b5c8ad45c3ab27c0b3076", + "cargo-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "e5e12be2c7126a7036c8adf573078a28b92611f5767cc9bd0a6f7c83081df103", + "clippy-1.92.0-aarch64-apple-darwin.tar.xz": "08c65b6cf8faae3861706f8c97acf2aa6b784ed9455354c3b13495a7cfe5cb84", + "clippy-1.92.0-aarch64-pc-windows-msvc.tar.xz": "2aa2f1288072ea1f870d6d860d09f5911c1305d506f344b65cf5e27b5070e262", + "clippy-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "333ab38c673b589468b8293b525e5704fb52515d9d516ee28d3d34dd5a63d3c3", + "clippy-1.92.0-x86_64-apple-darwin.tar.xz": "39cce87aab3d8b71350edcb3f943fba7bc59581ce1e65e158ee01e64cf0f1cf5", + "clippy-1.92.0-x86_64-pc-windows-msvc.tar.xz": "51a9a67931a3e50eb0c26b4c6a7ec2ef6ddd633319343a2d4767710c1e33b21f", + "clippy-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "2c1bf6e7da8ec50feba03fe188fc9a744ba59e2c6ece7970c13e201d08defa9a", + "rust-analyzer-1.92.0-aarch64-apple-darwin.tar.xz": "e2ec83302123119bbe04ed367fbb5d6d3575555faf7870f7b241f5bdeef3e6ed", + "rust-analyzer-1.92.0-aarch64-pc-windows-msvc.tar.xz": "fc645b480731828254c7691599c9d092032bfb5a728839cb3f2d52e7cce7fcd2", + "rust-analyzer-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "f18c06dab73f5cffab6b7c58a51c3bcbbcc962b08d4a56974e958cac229eb0cd", + "rust-analyzer-1.92.0-x86_64-apple-darwin.tar.xz": "a0a9ef444c3223f0b55ef1ec54945b109c7e7ea7cb8d3f0696290aa2ac51507e", + "rust-analyzer-1.92.0-x86_64-pc-windows-msvc.tar.xz": "edcac488265c48737bf615481970e0a0b07fa98380f49d6322f6d53327a1b51a", + "rust-analyzer-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "1b1dec1ca75c027968646a7524b2ebad070116df5fb625f8802deabe9c0b0b5a", + "rust-src-1.92.0.tar.xz": "333d45eeb76f210966dc5c1440b535dea5876ed0162f9286273c85e7a1e3cb29", + "rust-std-1.92.0-aarch64-apple-darwin.tar.xz": "ea619984fcb8e24b05dbd568d599b8e10d904435ab458dfba6469e03e0fd69aa", + "rust-std-1.92.0-aarch64-apple-ios-macabi.tar.xz": "d0453906db0abe9efb595e1ed59feb131a94c0312c0bc72da6482936667ff8da", + "rust-std-1.92.0-aarch64-apple-ios-sim.tar.xz": "9362b66fbaf2503276ea34f34b41b171269db9ba4dce05dde3472ea9d1852601", + "rust-std-1.92.0-aarch64-apple-ios.tar.xz": "81fb496f94a3f52ec2818a76a7107905b13b37d490ca849d22c0a7a7d7b0125e", + "rust-std-1.92.0-aarch64-linux-android.tar.xz": "ce6350bd43856c630773c93e40310989c6cb98a1178233c44e512a31761943d0", + "rust-std-1.92.0-aarch64-pc-windows-gnullvm.tar.xz": "4e79f57b80040757a3425568b5978986f026daf771649a64021c74bcc138214b", + "rust-std-1.92.0-aarch64-pc-windows-msvc.tar.xz": "b20c5c696af4ecfb683370ca0ee3c76ab8726fe6470ce9f1368d41a5b06ea065", + "rust-std-1.92.0-aarch64-unknown-fuchsia.tar.xz": "6021246b6c0d9d6104c0b350f7cd48a31d5707edaa8063f77f5636fe07bdb79d", + "rust-std-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "ce2ab42c09d633b0a8b4b65a297c700ae0fad47aae890f75894782f95be7e36d", + "rust-std-1.92.0-aarch64-unknown-linux-musl.tar.xz": "94b9f84f21d29825c55a27fbb6b4b9fb9296a4a841aa54d85b95c42445623363", + "rust-std-1.92.0-aarch64-unknown-none-softfloat.tar.xz": "0dc46fafaaa36f53eec49e14a69e1d6d9ac6f0b9624a01081ad311d8139a2be0", + "rust-std-1.92.0-aarch64-unknown-none.tar.xz": "ab6a2edab924739fc2c86e9f8fd8068b379e881a6261a177d66608d3ea4cacb1", + "rust-std-1.92.0-aarch64-unknown-uefi.tar.xz": "f98001222bf23743598382c232b08d3137035b53645a420a1425288d501808af", + "rust-std-1.92.0-arm-linux-androideabi.tar.xz": "d41ec7255556b605dda04201a23e4445b5b86bc6786c703f91eb985bddc9f4ca", + "rust-std-1.92.0-arm-unknown-linux-gnueabi.tar.xz": "35478e20f8cc13912b31f2905b313a2820ddae564b363a66ab7a5da39d12787f", + "rust-std-1.92.0-arm-unknown-linux-gnueabihf.tar.xz": "836ada282b65c57d71f9b7e6fb490832410c954aac905c5437fb0bf851b53c83", + "rust-std-1.92.0-arm-unknown-linux-musleabi.tar.xz": "91d3c5fdbda9ba2e778bb638e3a5d060f3021bbc7a60edf22b0035be4e611b30", + "rust-std-1.92.0-arm-unknown-linux-musleabihf.tar.xz": "20411e3858308add0dadde9ce2059d82cdd6c5339881fa93ac995e733df0f832", + "rust-std-1.92.0-armv7-linux-androideabi.tar.xz": "06ac2f08dcf5c480e7767c0541c9bd7460754ec3a369a4b7097b328eca28fab9", + "rust-std-1.92.0-armv7-unknown-linux-gnueabi.tar.xz": "3d5e3fb14441ea8e6fc6307cbd89efd69be42143ff7f2b8dfb19818ddca993c0", + "rust-std-1.92.0-armv7-unknown-linux-gnueabihf.tar.xz": "e3ac810db43067d8af9e17679d47534e871f1daad8cd0762e67da935681e9e19", + "rust-std-1.92.0-armv7-unknown-linux-musleabi.tar.xz": "89cbf7db934d543754b446a52398081ec40ee6b98ed5bca93ac1dbd5faf48c16", + "rust-std-1.92.0-armv7-unknown-linux-musleabihf.tar.xz": "c7c08a389bd351226fd52266bfe2d2c444597e1bbb5d0307da44bdfa4df62c99", + "rust-std-1.92.0-i686-linux-android.tar.xz": "e45832b005556f65c6d26f05f34bd4ab5ceea8d9b9fefc4175d52b0780ca89db", + "rust-std-1.92.0-i686-pc-windows-gnu.tar.xz": "b3eefe10d4aed3ccbeaff3ae9cd2e0e0a36894c0635d0e69af1c9a698679d75f", + "rust-std-1.92.0-i686-pc-windows-gnullvm.tar.xz": "e6d709f85dea51d81f2f1a030845b732b9f7761d95d93c57c7276b0a451c2993", + "rust-std-1.92.0-i686-pc-windows-msvc.tar.xz": "e5671b276047647e994a7cab99c90ee70c46787572fbe4e266a13c6edb84d5ce", + "rust-std-1.92.0-i686-unknown-freebsd.tar.xz": "e008a0506ec4d5eff30abdf376c7933e235670bd6c5e1131c52bcda097a21116", + "rust-std-1.92.0-i686-unknown-linux-gnu.tar.xz": "abc840631a4462a4c8ec61341110ff653ab2ef86ef3b10f84489d00cc8a9310d", + "rust-std-1.92.0-i686-unknown-linux-musl.tar.xz": "c796874b1343721f575203fa179dc258e09ac45cd95dd6c35c4d5979a3870494", + "rust-std-1.92.0-i686-unknown-uefi.tar.xz": "90da7759e28e62fb82454d4eb4e02ac14320b8da3372e02f9ca4f47f7afbfe40", + "rust-std-1.92.0-loongarch64-unknown-linux-gnu.tar.xz": "62e2568ebf6f1addc750a8c32dd1fa4fef8d27679cbac33b837afeb54f204819", + "rust-std-1.92.0-loongarch64-unknown-linux-musl.tar.xz": "274838eebb615e6d2719157aa53230cd0c3233a1e6f1c975c0f5978198c55da3", + "rust-std-1.92.0-loongarch64-unknown-none.tar.xz": "7e03cbb3aeb5a2c882433f2de0d096455bcab2465729cb0399d1b31e2d400075", + "rust-std-1.92.0-powerpc-unknown-linux-gnu.tar.xz": "c3e809a324b00eb53096c58df38645bb496c6560de334dfe04ed0b77c0605aaa", + "rust-std-1.92.0-powerpc64-unknown-linux-gnu.tar.xz": "2ce706afa4a46b6773340854de877fc63618a40e351298a4e3da8eb482619863", + "rust-std-1.92.0-powerpc64le-unknown-linux-gnu.tar.xz": "eba59766c2d9805c0a1fc82fd723acbb36569e1bec1088c037bba84d965f70ba", + "rust-std-1.92.0-powerpc64le-unknown-linux-musl.tar.xz": "8b515e18b6ac8f8d37ea3cabe644b7f571984333c3b4192b7f5877e79eae7893", + "rust-std-1.92.0-riscv32imac-unknown-none-elf.tar.xz": "5915223db6b8afa173f67eb4fe6f5aff2402351ed9abab1b370d0860be4af6c9", + "rust-std-1.92.0-riscv32imc-unknown-none-elf.tar.xz": "e1c6968ce25ab78f2c5b5460691763a2d39cb71b01d6d54c208d4a8b735b0584", + "rust-std-1.92.0-riscv64gc-unknown-linux-gnu.tar.xz": "8ee20dcf3b1063fa6069b3ce85e1fcf42794dfa783263314865cb53fff42d9e4", + "rust-std-1.92.0-riscv64gc-unknown-linux-musl.tar.xz": "f20d822309900fd6c7230688694baf91e900154e44e6247feca49b7b7a203a57", + "rust-std-1.92.0-riscv64gc-unknown-none-elf.tar.xz": "7eacf6a98786d58ef912643fd5aedc35111712e96a47b7e5d3ccddcdf9fb166d", + "rust-std-1.92.0-s390x-unknown-linux-gnu.tar.xz": "ebf944dc95015498d322504a54e4f9cdb28590f7790aa3a9eb86d6cf4b6c93ff", + "rust-std-1.92.0-sparc64-unknown-linux-gnu.tar.xz": "d85afb14120c3c7367338a565a920db653dccd4bc5062398791d7b62b89fd1fd", + "rust-std-1.92.0-thumbv6m-none-eabi.tar.xz": "f55de77126b60e1da38f8a5cdd127db872155ce9fbb53d4459502dd47b1dd476", + "rust-std-1.92.0-thumbv7em-none-eabi.tar.xz": "fdee017dcebfa8675220c20ca65b945b6eaee744d5d19b92cb0ca5480dd19ba6", + "rust-std-1.92.0-thumbv7em-none-eabihf.tar.xz": "6bfd083ce4917440fb4b04ca39ab4dadc9f40d9dc2775056899857bfa8911fd0", + "rust-std-1.92.0-thumbv7m-none-eabi.tar.xz": "7dc4c92e97db5ce1ddd9fbb7fbb1ad2d367f1c2e20d296a6d6427480c900c315", + "rust-std-1.92.0-thumbv8m.main-none-eabi.tar.xz": "61a6a80d03ebdb80ab06a044d4ec60e3c2bd8dc4d6011e920cf41592df4f0646", + "rust-std-1.92.0-thumbv8m.main-none-eabihf.tar.xz": "24c2f65371a2a5c6a40b51ae0e276ea9afff0479255f180f5e1549a0a4d58fb3", + "rust-std-1.92.0-wasm32-unknown-emscripten.tar.xz": "59b7adf18c0cc416a005fad7f704203b965905eb1c0ed9c556daa3c14048b9f4", + "rust-std-1.92.0-wasm32-unknown-unknown.tar.xz": "6c73f053ccd6adc886f802270ba960fd854e5e1111e4b5cfb875f1fdcfc0eb60", + "rust-std-1.92.0-wasm32-wasip1-threads.tar.xz": "feea056dd657a26560dfddfe4b53daeef3ded83c140b453b6dbdebaabd2a664c", + "rust-std-1.92.0-wasm32-wasip1.tar.xz": "8107dc35f0b6b744d998e766351419b4e0d27cddd6456c461337753a25f29fcd", + "rust-std-1.92.0-wasm32-wasip2.tar.xz": "e69ce601b6b24eea08b0d9e1fb0d9bf2a4188b3109353b272be4d995f687c943", + "rust-std-1.92.0-x86_64-apple-darwin.tar.xz": "6ce143bf9e83c71e200f4180e8774ab22c8c8c2351c88484b13ff13be82c8d57", + "rust-std-1.92.0-x86_64-apple-ios-macabi.tar.xz": "6a292d774653f2deaac743060ec68bfd5d7ff01d9b364e1a7d1e57a679650b47", + "rust-std-1.92.0-x86_64-apple-ios.tar.xz": "b6e38e5f8c9e6fb294681a7951301856b8f9424af4589e14493c0c939338814c", + "rust-std-1.92.0-x86_64-linux-android.tar.xz": "ffd39429435ff2f0763b940dd6afb4b9ccb1ed443eeef4fff9f1e9b3c5730026", + "rust-std-1.92.0-x86_64-pc-windows-gnu.tar.xz": "d4043304ef0e4792fb79a1153cbeca41308aac37cb1af3aa6bc3f0bb6d2276e1", + "rust-std-1.92.0-x86_64-pc-windows-gnullvm.tar.xz": "6169605b3073a7c2d6960bc1c74cb9cd6b65f45ee34e7ede02368e07ce4564cf", + "rust-std-1.92.0-x86_64-pc-windows-msvc.tar.xz": "b4e53a9c9b96a1a0618364791b7728a1c8978101ec6d1ee78fe930e1ef061994", + "rust-std-1.92.0-x86_64-unknown-freebsd.tar.xz": "151929a4255175d14b2cbcb69ef46d9217add23be268b9cd1446f8eab16616f2", + "rust-std-1.92.0-x86_64-unknown-fuchsia.tar.xz": "51ec26391d166e2f190a329919e3c7bd793861f02284aba461a086268725d9f1", + "rust-std-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "5f106805ed86ebf8df287039e53a45cf974391ef4d088c2760776b05b8e48b5d", + "rust-std-1.92.0-x86_64-unknown-linux-musl.tar.xz": "11f0b7efccdb5e7972e3c0fc23693a487abc28b624675c08161d055a016d527e", + "rust-std-1.92.0-x86_64-unknown-netbsd.tar.xz": "db6a8d3a091551701b12e40cc58d4a541adfb63f250074aae90d250329beb8de", + "rust-std-1.92.0-x86_64-unknown-none.tar.xz": "1d8420ab8eb241a35e38b76470277c722bd5a7aa4ac0c7a565ad6f30b37cb852", + "rust-std-1.92.0-x86_64-unknown-uefi.tar.xz": "1b849250cf095269f3a2c7bc2087a919386da7da28e80dc289e6268bc705142d", + "rustc-1.92.0-aarch64-apple-darwin.tar.xz": "15dee753c9217dff4cf45d734b29dc13ce6017d8a55fe34eed75022b39a63ff0", + "rustc-1.92.0-aarch64-pc-windows-msvc.tar.xz": "07ba5606143de3bc916455714f67732fca05805591396a8190d5e88b8863eea3", + "rustc-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "7c8706fad4c038b5eacab0092e15db54d2b365d5f3323ca046fe987f814e7826", + "rustc-1.92.0-src.tar.xz": "ebee170bfe4c4dfc59521a101de651e5534f4dae889756a5c97ca9ea40d0c307", + "rustc-1.92.0-x86_64-apple-darwin.tar.xz": "0facbd5d2742c8e97c53d59c9b5b81db6088cfc285d9ecb99523a50d6765fc5c", + "rustc-1.92.0-x86_64-pc-windows-msvc.tar.xz": "6aec5aba5384ce1041538e71ebebf671d82e29f4fe697bc7844626d94b0dbfe6", + "rustc-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "78b2dd9c6b1fcd2621fa81c611cf5e2d6950690775038b585c64f364422886e0", + "rustfmt-1.92.0-aarch64-apple-darwin.tar.xz": "5d8ea865a7999dc9141603be8a9352745bf8440da051eb1c43f0fcaaf6845441", + "rustfmt-1.92.0-aarch64-pc-windows-msvc.tar.xz": "e626e08df361c5a9127e0e4b5d73f87fd17ed30cc471887ebc033bebe97c0ff2", + "rustfmt-1.92.0-aarch64-unknown-linux-gnu.tar.xz": "1dce37aea2a7cb801f1756ffc531d7140428315a3d2c2f836272547eb7b9dacd", + "rustfmt-1.92.0-x86_64-apple-darwin.tar.xz": "e038bda323ed7f4d417efc5be44c4245d74b8394f9f8393b9d464d662c3a9499", + "rustfmt-1.92.0-x86_64-pc-windows-msvc.tar.xz": "3761b2e8a18d672b2804b0d1864dc122b7bc54343d6a109135c7843de7fa2ace", + "rustfmt-1.92.0-x86_64-unknown-linux-gnu.tar.xz": "38951ee55f21e9170236fc98c8ba373ae4338d863087c6b0a5fa8c4e797d52c4" + } + }, + "factsVersions": {} } diff --git a/local-remote-execution/generated-cc/cc/BUILD b/local-remote-execution/generated-cc/cc/BUILD index a3a3f6a8d..705f4607e 100644 --- a/local-remote-execution/generated-cc/cc/BUILD +++ b/local-remote-execution/generated-cc/cc/BUILD @@ -122,10 +122,10 @@ cc_toolchain_config( coverage_link_flags = ["--coverage"], cpu = "k8", cxx_builtin_include_directories = [ - "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include", - "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include", - "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share", - "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1", + "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include", + "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include", + "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share", + "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk", ], cxx_flags = ["-std=c++14"], @@ -136,8 +136,8 @@ cc_toolchain_config( ]}, host_system_name = "x86_64-unknown-linux-gnu", link_flags = [ - "-fuse-ld=/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/ld.mold", - "-B/nix/store/5b69ajvn84dh0hyick8l3s0fl51kv776-customClang/bin", + "-fuse-ld=/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/ld.mold", + "-B/nix/store/n4rzbc1y6z5dj0wr884rmn85lz0dfi1l-customClang/bin", "-Wl,-no-as-needed", "-Wl,-z,relro,-z,now", ], @@ -162,19 +162,19 @@ cc_toolchain_config( target_libc = "glibc_2.38", target_system_name = "local", tool_paths = { - "ar": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/ar", - "ld": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/ld", + "ar": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/ar", + "ld": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/ld", "llvm-cov": "None", "llvm-profdata": "None", "cpp": "/usr/bin/cpp", - "gcc": "/nix/store/5b69ajvn84dh0hyick8l3s0fl51kv776-customClang/bin/customClang", - "dwp": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/dwp", + "gcc": "/nix/store/n4rzbc1y6z5dj0wr884rmn85lz0dfi1l-customClang/bin/customClang", + "dwp": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/dwp", "gcov": "None", - "nm": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/nm", - "objcopy": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/objcopy", - "objdump": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/objdump", - "strip": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/strip", - "c++filt": "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/c++filt", + "nm": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/nm", + "objcopy": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/objcopy", + "objdump": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/objdump", + "strip": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/strip", + "c++filt": "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/c++filt", "parse_headers": "cc_wrapper.sh", "validate_static_library": "validate_static_library.sh", }, diff --git a/local-remote-execution/generated-cc/cc/builtin_include_directory_paths b/local-remote-execution/generated-cc/cc/builtin_include_directory_paths index 5e3975521..57b76b41c 100644 --- a/local-remote-execution/generated-cc/cc/builtin_include_directory_paths +++ b/local-remote-execution/generated-cc/cc/builtin_include_directory_paths @@ -1,11 +1,11 @@ This file is generated by cc_configure and contains builtin include directories -that /nix/store/5b69ajvn84dh0hyick8l3s0fl51kv776-customClang/bin/customClang reported. This file is a dependency of every compilation action and +that /nix/store/n4rzbc1y6z5dj0wr884rmn85lz0dfi1l-customClang/bin/customClang reported. This file is a dependency of every compilation action and changes to it will be reflected in the action cache key. When some of these paths change, Bazel will make sure to rerun the action, even though none of declared action inputs or the action commandline changes. -/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include -/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include -/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share -/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1 +/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include +/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include +/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share +/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk diff --git a/local-remote-execution/generated-cc/cc/cc_wrapper.sh b/local-remote-execution/generated-cc/cc/cc_wrapper.sh index 320f13578..9b30edce2 100644 --- a/local-remote-execution/generated-cc/cc/cc_wrapper.sh +++ b/local-remote-execution/generated-cc/cc/cc_wrapper.sh @@ -1,4 +1,4 @@ -#!/nix/store/i7hwka78f6i34v4r211ynr6nnafcba7f-bash/bin/bash +#!/nix/store/x4xf1dbpn5q4lkx1a5c9mxy5300gacc1-bash/bin/bash # # Copyright 2015 The Bazel Authors. All rights reserved. # @@ -44,7 +44,7 @@ done # Set-up the environment # Call the C++ compiler -/nix/store/5b69ajvn84dh0hyick8l3s0fl51kv776-customClang/bin/customClang "$@" +/nix/store/n4rzbc1y6z5dj0wr884rmn85lz0dfi1l-customClang/bin/customClang "$@" # Generate an empty file if header processing succeeded. if [[ ${OUTPUT} == *.h.processed ]]; then diff --git a/local-remote-execution/generated-cc/cc/module.modulemap b/local-remote-execution/generated-cc/cc/module.modulemap index d281ed188..db50e1e72 100644 --- a/local-remote-execution/generated-cc/cc/module.modulemap +++ b/local-remote-execution/generated-cc/cc/module.modulemap @@ -1,3462 +1,3463 @@ module "crosstool" [system] { - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_builtin_vars.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_cmath.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_complex_builtins.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_device_functions.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_intrinsics.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_libdevice_declares.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_math.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_math_forward_declares.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_runtime_wrapper.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_cuda_texture_intrinsics.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_hip_cmath.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_hip_libdevice_declares.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_hip_math.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_hip_runtime_wrapper.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_hip_stdlib.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__clang_spirv_builtins.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__float_float.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__float_header_macro.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__float_infinity_nan.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stdarg___gnuc_va_list.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stdarg___va_copy.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stdarg_header_macro.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stdarg_va_arg.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stdarg_va_copy.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stdarg_va_list.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_header_macro.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_max_align_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_null.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_nullptr_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_offsetof.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_ptrdiff_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_rsize_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_size_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_unreachable.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_wchar_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__stddef_wint_t.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__wmmintrin_aes.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/__wmmintrin_pclmul.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/adcintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/adxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/altivec.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amdgpuintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ammintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amo.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxavx512intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxcomplexintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxfp16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxfp8intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxmovrsintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/amxtf32intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/andes_vector.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm64intr.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_acle.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_bf16.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_cde.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_cmse.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_fp16.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_mve.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_neon.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_neon_sve_bridge.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_sme.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_sve.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/arm_vector_types.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/armintr.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2_512bf16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2_512convertintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2_512minmaxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2_512niintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2_512satcvtdsintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2_512satcvtintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2bf16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2convertintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2copyintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2minmaxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2niintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2satcvtdsintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx10_2satcvtintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx2intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512bf16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512bitalgintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512bwintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512cdintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512dqintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512fintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512fp16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512ifmaintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512ifmavlintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vbmi2intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vbmiintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vbmivlintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlbf16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlbitalgintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlbwintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlcdintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vldqintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlfp16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlvbmi2intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlvnniintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vlvp2intersectintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vnniintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vp2intersectintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vpopcntdqintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avx512vpopcntdqvlintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avxifmaintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avxneconvertintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avxvnniint16intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avxvnniint8intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/avxvnniintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/bmi2intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/bmiintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/builtins.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cet.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cetintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cldemoteintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/clflushoptintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/clwbintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/clzerointrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cmpccxaddintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cpuid.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/crc32intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/__utility/declval.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/algorithm" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/bits/basic_string.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/bits/basic_string.tcc" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/bits/c++config.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/bits/shared_ptr_base.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/cmath" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/complex" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/cuda_wrappers/new" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/emmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/enqcmdintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/f16cintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/float.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/fma4intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/fmaintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/fxsrintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/gfniintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/gpuintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/hexagon_circ_brev_intrinsics.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/hexagon_protos.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/hexagon_types.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/hresetintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/htmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/htmxlintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/hvx_hexagon_protos.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ia32intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/immintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/intrin0.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/inttypes.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/invpcidintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/iso646.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/keylockerintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/larchintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/lasxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/limits.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/assert.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/ctype.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/inttypes.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/stdio.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/stdlib.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/string.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_libc_wrappers/time.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_offload_wrappers/__llvm_offload.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_offload_wrappers/__llvm_offload_device.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/llvm_offload_wrappers/__llvm_offload_host.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/lsxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/lwpintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/lzcntintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/mm3dnow.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/mm_malloc.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/mmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/module.modulemap" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/movdirintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/movrs_avx10_2_512intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/movrs_avx10_2intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/movrsintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/msa.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/mwaitxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/nmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/nvptxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/opencl-c-base.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/opencl-c.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/__clang_openmp_device_functions.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/cmath" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/complex" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/complex.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/complex_cmath.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/math.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/openmp_wrappers/new" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/pconfigintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/pkuintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/pmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/popcntintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/bmi2intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/bmiintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/emmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/immintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/mm_malloc.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/mmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/nmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/pmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/smmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/tmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/x86gprintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/x86intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ppc_wrappers/xmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/prfchiintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/prfchwintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ptrauth.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/ptwriteintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/raointintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/rdpruintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/rdseedintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_bitmanip.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_corev_alu.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_crypto.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_mips.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_nds.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_ntlh.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/riscv_vector.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/rtmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/s390intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/serializeintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/sgxintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/sha512intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/shaintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/sifive_vector.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/sm3intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/sm4evexintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/sm4intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/smmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/spirvintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdalign.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdarg.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdatomic.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdbool.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdckdint.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdcountof.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stddef.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stddefer.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdint.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/stdnoreturn.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/tbmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/tgmath.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/tmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/tsxldtrkintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/uintrintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/unwind.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/usermsrintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/vadefs.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/vaesintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/varargs.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/vecintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/velintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/velintrin_approx.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/velintrin_gen.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/vpclmulqdqintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/waitpkgintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/wasm_simd128.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/wbnoinvdintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/wmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/x86gprintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/x86intrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xmmintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xopintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xsavecintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xsaveintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xsaveoptintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xsavesintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/xtestintrin.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/yvals_core.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/include/zos_wrappers/builtins.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/a.out.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/aio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/aliases.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/alloca.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/argp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/argz.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/arpa/ftp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/arpa/inet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/arpa/nameser.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/arpa/nameser_compat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/arpa/telnet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/arpa/tftp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/auxvec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/bitsperlong.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/bpf_perf_event.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/errno-base.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/errno.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/fcntl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/hugetlb_encode.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/int-l64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/int-ll64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/ioctls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/ipcbuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/kvm_para.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/mman-common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/mman.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/msgbuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/param.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/poll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/posix_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/resource.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/sembuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/setup.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/shmbuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/siginfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/signal-defs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/signal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/sockios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/stat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/statfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/swab.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/termbits-common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/termbits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/termios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/ucontext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm-generic/unistd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/a.out.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/amd_hsmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/auxvec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/bitsperlong.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/boot.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/bootparam.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/bpf_perf_event.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/byteorder.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/debugreg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/e820.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/elf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/errno.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/fcntl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/hw_breakpoint.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/hwcap2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ioctls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ipcbuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ist.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/kvm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/kvm_para.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/kvm_perf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ldt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/mce.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/mman.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/msgbuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/msr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/mtrr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/param.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/perf_regs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/poll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/posix_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/posix_types_32.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/posix_types_64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/posix_types_x32.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/prctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/processor-flags.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ptrace-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ptrace.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/resource.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/sembuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/setup.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/setup_data.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/sgx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/shmbuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/sigcontext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/sigcontext32.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/siginfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/signal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/sockios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/stat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/statfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/svm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/swab.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/termbits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/termios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/ucontext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/unistd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/unistd_32.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/unistd_64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/unistd_x32.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/vm86.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/vmx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/asm/vsyscall.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/assert.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/a.out.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/argp-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/atomic_wide_counter.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/byteswap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/cmathcalls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/confname.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/cpu-set.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/dirent.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/dirent_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/dl_find_object.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/dlfcn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/elfclass.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/endian.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/endianness.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/environments.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/epoll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/err-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/errno.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/error-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/error.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/eventfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/fcntl-linux.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/fcntl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/fcntl2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/fenv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/floatn-common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/floatn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/flt-eval-method.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/fp-fast.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/fp-logb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/getopt_core.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/getopt_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/getopt_posix.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/hwcap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/in.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/indirect-return.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/inet-fortified-decl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/inet-fortified.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/initspin.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/inotify.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ioctl-types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ioctls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ipc-perm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ipc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ipctypes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/iscanonical.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/libc-header-start.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/libm-simd-decl-stubs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/link.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/link_lavcurrent.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/local_lim.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/locale.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/long-double.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/math-vector.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mathcalls-helper-functions.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mathcalls-macros.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mathcalls-narrow.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mathcalls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mathdef.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mman-linux.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mman-map-flags-generic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mman-shared.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mman.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mman_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/monetary-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mqueue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/mqueue2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/msq.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/netdb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/param.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/platform/features.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/platform/x86.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/poll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/poll2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/posix1_lim.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/posix2_lim.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/posix_opt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/printf-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/procfs-extra.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/procfs-id.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/procfs-prregset.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/procfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/pthread_stack_min-dynamic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/pthread_stack_min.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/pthreadtypes-arch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/pthreadtypes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ptrace-shared.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/resource.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/rseq.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sched.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/select-decl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/select.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/select2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sem.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/semaphore.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/setjmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/setjmp2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/shm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/shmlba.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sigaction.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sigcontext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sigevent-consts.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/siginfo-arch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/siginfo-consts-arch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/siginfo-consts.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/signal_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/signalfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/signum-arch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/signum-generic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sigstack.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sigstksz.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sigthread.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sockaddr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/socket-constants.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/socket2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/socket_type.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/spawn_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/ss_flags.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stab.def" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/statfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/statvfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/statx-generic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/statx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdint-intn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdint-least.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdint-uintn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdio-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdio2-decl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdio2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdio_lim.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdlib-bsearch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdlib-float.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdlib-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/stdlib.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/string_fortified.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/strings_fortified.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/struct_mutex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/struct_rwlock.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/struct_stat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/struct_stat_time64_helper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/syscall.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/syslog-decl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/syslog-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/syslog-path.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/syslog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/sysmacros.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-baud.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-c_cc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-c_cflag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-c_iflag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-c_lflag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-c_oflag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-cbaud.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-misc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-struct.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios-tcflow.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/termios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/thread-shared-types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/time.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/time64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/timerfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/timesize.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/timex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/FILE.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__FILE.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__fpos64_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__fpos_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__locale_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__mbstate_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__sigset_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/__sigval_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/clock_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/clockid_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/cookie_io_functions_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/error_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/idtype_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/locale_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/mbstate_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/res_state.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/sig_atomic_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/sigevent_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/siginfo_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/sigset_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/sigval_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/stack_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_FILE.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct___jmp_buf_tag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_iovec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_itimerspec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_msqid64_ds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_msqid64_ds_helper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_msqid_ds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_osockaddr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_rusage.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_sched_param.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_semid64_ds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_semid64_ds_helper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_semid_ds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_shmid64_ds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_shmid64_ds_helper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_shmid_ds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_sigstack.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_statx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_statx_timestamp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_timeb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_timespec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_timeval.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/struct_tm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/time_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/timer_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/types/wint_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/typesizes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/uintn-identity.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/uio-ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/uio_lim.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/unistd-decl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/unistd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/unistd_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/utmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/utmpx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/utsname.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/waitflags.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/waitstatus.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/wchar-ldbl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/wchar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/wchar2-decl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/wchar2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/wctype-wchar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/wordsize.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/bits/xopen_lim.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/byteswap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/complex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/config/kernel.release" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/cpio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ctype.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/cxl/features.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/dirent.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/dlfcn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/amdgpu_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/amdxdna_accel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/armada_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/asahi_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/drm_fourcc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/drm_mode.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/drm_sarea.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/etnaviv_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/exynos_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/habanalabs_accel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/i915_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/ivpu_accel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/lima_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/msm_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/nouveau_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/nova_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/omap_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/panfrost_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/panthor_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/pvr_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/qaic_accel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/qxl_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/radeon_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/rocket_accel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/tegra_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/v3d_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/vc4_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/vgem_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/virtgpu_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/vmwgfx_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/drm/xe_drm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/elf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/endian.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/envz.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/err.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/errno.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/error.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/execinfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fcntl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/features-time64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/features.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fenv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/finclude/math-vector-fortran.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fmtmsg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fnmatch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fpu_control.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fstab.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fts.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ftw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fwctl/cxl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fwctl/fwctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fwctl/mlx5.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/fwctl/pds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gconv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/getopt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/glob.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gnu-versions.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gnu/lib-names-64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gnu/lib-names.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gnu/libc-version.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gnu/stubs-64.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gnu/stubs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/grp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/gshadow.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/iconv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ieee754.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ifaddrs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/inttypes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/langinfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/lastlog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/libgen.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/libintl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/limits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/link.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/a.out.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/acct.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/acrn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/adb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/adfs_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/affs_hardblocks.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/agpgart.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/aio_abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/am437x-vpfe.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/amt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/android/binder.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/android/binder_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/android/binderfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/apm_bios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/arcfb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/arm_sdei.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/aspeed-lpc-ctrl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/aspeed-p2a-ctrl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/aspeed-video.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atalk.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm_eni.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm_he.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm_idt77105.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm_nicstar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm_tcp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atm_zatm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmapi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmarp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmbr2684.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmclip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmioc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmlec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmmpc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmppp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmsap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/atmsvc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/audit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/auto_dev-ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/auto_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/auto_fs4.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/auxvec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ax25.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/batadv_packet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/batman_adv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/baycom.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bcm933xx_hcs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bfs_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/binfmts.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/blk-crypto.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/blkdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/blkpg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/blktrace_api.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/blkzoned.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bpf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bpf_common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bpf_perf_event.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bpqether.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bsg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/bt-bmc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/btf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/btrfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/btrfs_tree.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/byteorder/big_endian.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/byteorder/little_endian.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cachefiles.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/caif/caif_socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/caif/if_caif.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/bcm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/error.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/gw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/isotp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/j1939.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/raw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/can/vxcan.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/capability.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/capi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cciss_defs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cciss_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ccs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cdrom.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cec-funcs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cfm_bridge.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cgroupstats.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/chio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cifs/cifs_mount.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cifs/cifs_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/close_range.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cn_proc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/coda.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/coff.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/comedi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/connector.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/const.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/coredump.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/coresight-stm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/counter.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/counter/microchip-tcb-capture.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cramfs_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cryptouser.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cuda.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cxl_mem.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cyclades.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/cycx_cfm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dcbnl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dccp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/devlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dlm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dlm_device.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dlm_plock.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dlmconstants.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dm-ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dm-log-userspace.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dma-buf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dma-heap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dns_resolver.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dpll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dqblk_xfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/audio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/ca.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/dmx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/frontend.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/net.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/osd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/version.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dvb/video.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/dw100.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/edd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/efs_fs_sb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/elf-em.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/elf-fdpic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/elf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/errno.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/errqueue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/erspan.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ethtool.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ethtool_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ethtool_netlink_generated.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/eventfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/eventpoll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/exfat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ext4.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/f2fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fadvise.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/falloc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fanotify.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fcntl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fdreg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fib_rules.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fiemap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/filter.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/firewire-cdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/firewire-constants.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fou.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fpga-dfl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fscrypt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fsi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fsl_hypervisor.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fsl_mc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fsmap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fsverity.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/fuse.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/futex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/gameport.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/gen_stats.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/genetlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/genwqe/genwqe_card.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/gfs2_ondisk.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/gpio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/gsmmux.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/gtp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/handshake.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hash_info.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hdlc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hdlc/ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hdlcdrv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hdreg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hiddev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hidraw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hpet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hsi/cs-protocol.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hsi/hsi_char.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hsr_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hw_breakpoint.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/hyperv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/i2c-dev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/i2c.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/i2o-dev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/i8k.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/icmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/icmpv6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/idxd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_addr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_addrlabel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_alg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_arcnet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_arp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_bonding.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_bridge.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_eql.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_ether.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_fc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_fddi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_hippi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_infiniband.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_link.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_ltalk.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_macsec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_packet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_phonet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_plip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_ppp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_pppol2tp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_pppox.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_slip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_team.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_tun.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_tunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_vlan.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_x25.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/if_xdp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ife.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/igmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/iio/buffer.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/iio/events.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/iio/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ila.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/in.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/in6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/in_route.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/inet_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/inotify.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/input-event-codes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/input.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/io_uring.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/io_uring/mock_file.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/io_uring/query.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ioam6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ioam6_genl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ioam6_iptunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/iommufd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ioprio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ip6_tunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ip_vs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipmi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipmi_bmc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipmi_msgdefs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipmi_ssif_bmc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipsec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipv6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ipv6_route.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/irqnr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/isdn/capicmd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/iso_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/isst_if.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ivtv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ivtvfb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/jffs2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/joystick.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kcm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kcmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kcov.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kdev_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kernel-page-flags.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kernel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kernelcapi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kexec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/keyboard.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/keyctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kfd_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kfd_sysfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kvm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/kvm_para.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/l2tp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/landlock.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/libc-compat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/limits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/lirc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/llc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/loadpin.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/lockd_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/loop.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/lp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/lsm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/lwtunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/magic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/major.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/map_to_14segment.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/map_to_7segment.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/matroxfb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/max2175.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mctp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mdio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media-bus-format.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media/amlogic/c3-isp-config.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media/raspberrypi/pisp_be_config.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media/raspberrypi/pisp_common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media/raspberrypi/pisp_fe_config.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/media/raspberrypi/pisp_fe_statistics.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mei.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mei_uuid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/membarrier.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/memfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mempolicy.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mii.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/minix_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/misc/bcm_vk.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mman.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mmc/ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mmtimer.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/module.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mount.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mpls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mpls_iptunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mptcp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mptcp_pm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mqueue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mroute.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mroute6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mrp_bridge.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/msdos_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/msg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mshv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/mtio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nbd-netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nbd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ncsi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ndctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/neighbour.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/net.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/net_dropmon.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/net_namespace.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/net_shaper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/net_tstamp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netconf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netdevice.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/ipset/ip_set.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/ipset/ip_set_bitmap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/ipset/ip_set_hash.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/ipset/ip_set_list.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_conntrack_common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_conntrack_ftp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_conntrack_sctp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_conntrack_tcp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_conntrack_tuple_common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_log.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_nat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_synproxy.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_tables.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nf_tables_compat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_acct.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_compat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_conntrack.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_cthelper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_cttimeout.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_hook.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_log.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_osf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/nfnetlink_queue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/x_tables.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_AUDIT.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_CHECKSUM.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_CLASSIFY.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_CONNMARK.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_CONNSECMARK.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_CT.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_DSCP.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_HMARK.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_IDLETIMER.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_LED.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_LOG.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_MARK.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_NFLOG.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_NFQUEUE.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_RATEEST.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_SECMARK.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_SYNPROXY.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_TCPMSS.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_TCPOPTSTRIP.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_TEE.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_TPROXY.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_addrtype.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_bpf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_cgroup.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_cluster.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_comment.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_connbytes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_connlabel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_connlimit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_connmark.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_conntrack.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_cpu.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_dccp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_devgroup.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_dscp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_ecn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_esp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_hashlimit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_helper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_ipcomp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_iprange.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_ipvs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_l2tp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_length.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_limit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_mac.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_mark.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_multiport.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_nfacct.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_osf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_owner.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_physdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_pkttype.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_policy.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_quota.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_rateest.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_realm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_recent.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_rpfilter.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_sctp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_set.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_state.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_statistic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_string.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_tcpmss.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_tcpudp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_time.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter/xt_u32.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_arp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_arp/arp_tables.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_arp/arpt_mangle.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_802_3.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_among.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_arp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_arpreply.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_ip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_ip6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_limit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_log.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_mark_m.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_mark_t.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_nat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_nflog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_pkttype.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_redirect.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_stp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebt_vlan.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_bridge/ebtables.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ip_tables.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_ECN.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_LOG.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_REJECT.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_TTL.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_ah.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_ecn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv4/ipt_ttl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6_tables.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_HL.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_LOG.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_NPT.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_REJECT.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_ah.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_frag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_hl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_ipv6header.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_mh.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_opts.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_rt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netfilter_ipv6/ip6t_srh.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netlink_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/netrom.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nexthop.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs3.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs4.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs4_mount.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs_idmap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfs_mount.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfsacl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfsd/cld.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfsd/debug.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfsd/export.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfsd/stats.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nfsd_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nilfs2_api.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nilfs2_ondisk.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nitro_enclaves.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nl80211-vnd-intel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nl80211.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/npcm-video.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nsfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nsm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ntsync.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nubus.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nvme_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/nvram.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/omap3isp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/omapfb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/oom.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/openat2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/openvswitch.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ovpn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/packet_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/papr_pdsm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/param.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/parport.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/patchkey.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pci.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pci_regs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pcitest.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/perf_event.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/personality.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pfkeyv2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pfrut.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/phantom.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/phonet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pidfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pkt_cls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pkt_sched.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pktcdvd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pmu.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/poll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/posix_acl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/posix_acl_xattr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/posix_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ppdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ppp-comp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ppp-ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ppp_defs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pps.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pps_gen.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/prctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/psample.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/psci.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/psp-dbc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/psp-sev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/psp-sfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/psp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ptp_clock.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ptrace.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/pwm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/qemu_fw_cfg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/qnx4_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/qnxtypes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/qrtr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/quota.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/radeonfb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/raid/md_p.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/raid/md_u.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/random.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/reboot.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/remoteproc_cdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/resource.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rfkill.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rio_cm_cdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rio_mport_cdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rkisp1-config.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/romfs_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rose.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/route.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rpl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rpl_iptunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rpmsg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rpmsg_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rseq.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rtc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rtnetlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/rxrpc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/scc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sched.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sched/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/scif_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/screen_info.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sctp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/seccomp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/securebits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sed-opal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/seg6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/seg6_genl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/seg6_hmac.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/seg6_iptunnel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/seg6_local.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/selinux_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sem.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/serial.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/serial_core.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/serial_reg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/serio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sev-guest.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/shm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/signal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/signalfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/smc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/smc_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/smiapp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/snmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sock_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sockios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sonet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sonypi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sound.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/soundcard.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/spi/spi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/spi/spidev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/stat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/stddef.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/stm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/string.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sunrpc/debug.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/surface_aggregator/cdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/surface_aggregator/dtx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/suspend_ioctls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/swab.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/switchtec_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sync_file.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/synclink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sysctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/sysinfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/target_core_user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/taskstats.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_bpf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_connmark.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_csum.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_ct.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_ctinfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_defact.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_gact.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_gate.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_ife.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_mirred.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_mpls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_nat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_pedit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_sample.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_skbedit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_skbmod.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_tunnel_key.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_act/tc_vlan.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_ematch/tc_em_cmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_ematch/tc_em_ipt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_ematch/tc_em_meta.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_ematch/tc_em_nbyte.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tc_ematch/tc_em_text.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tcp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tcp_metrics.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tdx-guest.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tee.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/termios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/thermal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/thp7312.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/time.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/time_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/timerfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/times.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/timex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tiocl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tipc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tipc_config.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tipc_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tipc_sockets_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/toshiba.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tps6594_pfsm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/trace_mmap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tty.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/tty_flags.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ublk_cmd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/udf_fs_i.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/udmabuf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/udp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/uhid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/uinput.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/uio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/uleds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/ultrasound.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/um_timetravel.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/un.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/unistd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/unix_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/audio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/cdc-wdm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/cdc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/ch11.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/ch9.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/charger.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/functionfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/g_hid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/g_printer.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/g_uvc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/gadgetfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/midi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/raw_gadget.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/tmc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usb/video.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usbdevice_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/usbip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/user_events.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/userfaultfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/userio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/utime.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/utsname.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/uuid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/uvcvideo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/v4l2-common.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/v4l2-controls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/v4l2-dv-timings.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/v4l2-mediabus.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/v4l2-subdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vbox_err.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vbox_vmmdev_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vboxguest.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vdpa.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vduse.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/version.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vesa.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/veth.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vfio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vfio_ccw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vfio_zdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vhost.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vhost_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/videodev2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_9p.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_balloon.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_blk.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_bt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_config.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_console.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_crypto.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_fs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_gpio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_gpu.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_i2c.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_ids.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_input.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_iommu.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_mem.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_mmio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_net.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_pci.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_pcidev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_pmem.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_ring.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_rng.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_rtc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_scmi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_scsi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_snd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_spi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/virtio_vsock.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vm_sockets.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vm_sockets_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vmclock-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vmcore.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vsockmon.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/vtpm_proxy.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/wait.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/watch_queue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/watchdog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/wireguard.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/wireless.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/wmi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/wwan.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/x25.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/xattr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/xdp_diag.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/xfrm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/xilinx-v4l2-controls.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/zorro.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/linux/zorro_ids.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/locale.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/malloc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/math.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mcheck.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/memory.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/amd-apml.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/fastrpc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/mrvl_cn10k_dpi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/ocxl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/pvpanic.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/uacce/hisi_qm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/uacce/uacce.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/misc/xilinx_sdfec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mntent.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/monetary.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mqueue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mtd/inftl-user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mtd/mtd-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mtd/mtd-user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mtd/nftl-user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/mtd/ubi-user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/ethernet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/if.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/if_arp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/if_packet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/if_ppp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/if_shaper.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/if_slip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/ppp-comp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/ppp_defs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/net/route.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netash/ash.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netatalk/at.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netax25/ax25.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netdb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/neteconet/ec.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/ether.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/icmp6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/if_ether.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/if_fddi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/if_tr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/igmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/in.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/in_systm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/ip.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/ip6.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/ip_icmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/tcp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netinet/udp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netipx/ipx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netiucv/iucv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netpacket/packet.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netrom/netrom.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/netrose/rose.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/nfs/nfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/nl_types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/nss.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/obstack.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/paths.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/poll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/printf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/proc_service.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/protocols/routed.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/protocols/rwhod.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/protocols/talkd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/protocols/timed.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/pthread.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/pty.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/pwd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/bnxt_re-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/cxgb4-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/efa-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/erdma-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/hfi/hfi1_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/hfi/hfi1_user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/hns-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ib_user_ioctl_cmds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ib_user_ioctl_verbs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ib_user_mad.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ib_user_sa.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ib_user_verbs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ionic-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/irdma-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/mana-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/mlx4-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/mlx5-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/mlx5_user_ioctl_cmds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/mlx5_user_ioctl_verbs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/mthca-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/ocrdma-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/qedr-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/rdma_netlink.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/rdma_user_cm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/rdma_user_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/rdma_user_ioctl_cmds.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/rdma_user_rxe.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/rvt-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/siw-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rdma/vmw_pvrdma-abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/re_comp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/regex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/regexp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/regulator/regulator.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/resolv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/rpc/netdb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sched.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/scsi/scsi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/scsi/scsi_ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/scsi/sg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/search.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/semaphore.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/setjmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sgtty.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/shadow.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/signal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/asequencer.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/asoc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/asound.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/asound_fm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/compress_offload.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/compress_params.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/emu10k1.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/fcp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/firewire.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/hdsp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/hdspm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/intel/avs/tokens.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/sb16_csp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/scarlett2.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/sfnt_info.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/skl-tplg-interface.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/snd_ar_tokens.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/snd_sst_tokens.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/sof/abi.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/sof/fw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/sof/header.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/sof/tokens.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/tlv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sound/usb_stream.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/spawn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stab.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stdbit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stdc-predef.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stdint.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stdio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stdio_ext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/stdlib.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/string.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/strings.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/acct.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/auxv.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/bitypes.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/cdefs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/debugreg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/dir.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/elf.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/epoll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/errno.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/eventfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/fanotify.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/fcntl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/file.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/fsuid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/gmon.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/gmon_out.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/inotify.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/io.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/ioctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/ipc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/kd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/klog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/mman.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/mount.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/msg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/mtio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/param.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/pci.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/perm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/personality.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/pidfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/platform/x86.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/poll.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/prctl.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/procfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/profil.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/ptrace.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/queue.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/quota.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/random.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/raw.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/reboot.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/reg.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/resource.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/rseq.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/select.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/sem.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/sendfile.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/shm.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/signal.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/signalfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/single_threaded.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/socket.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/socketvar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/soundcard.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/stat.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/statfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/statvfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/swap.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/syscall.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/sysinfo.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/syslog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/sysmacros.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/termios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/time.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/timeb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/timerfd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/times.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/timex.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/ttychars.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/ttydefaults.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/types.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/ucontext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/uio.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/un.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/unistd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/user.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/utsname.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/vfs.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/vlimit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/vm86.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/vt.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/wait.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sys/xattr.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/syscall.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/sysexits.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/syslog.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/tar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/termios.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/tgmath.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/thread_db.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/threads.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/time.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ttyent.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/uchar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ucontext.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/ulimit.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/unistd.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/utime.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/utmp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/utmpx.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/values.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/video/edid.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/video/sisfb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/video/uvesafb.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/wait.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/wchar.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/wctype.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/wordexp.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/xen/evtchn.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/xen/gntalloc.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/xen/gntdev.h" - textual header "/nix/store/h0ip0h6qp7kc2wm7mwjaglkxxbzmjri4-glibc-2.42-51-dev/include/xen/privcmd.h" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share/asan_ignorelist.txt" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share/cfi_ignorelist.txt" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share/dfsan_abilist.txt" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share/hwasan_ignorelist.txt" - textual header "/nix/store/mg0lv9jhy5kr3ra9dya3yps5p8qd5mkn-clang-wrapper-22.1.0-rc3/resource-root/share/msan_ignorelist.txt" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/adjacent_find.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/all_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/any_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/binary_search.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/clamp.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/comp.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/comp_ref_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/copy_backward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/copy_move_common.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/copy_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/count.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/count_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/equal.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/equal_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/fill.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/fill_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/find.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/find_end.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/find_first_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/find_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/find_if_not.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/find_segment_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/for_each.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/for_each_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/for_each_n_segment.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/for_each_segment.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/generate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/generate_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/half_positive.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/in_found_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/in_fun_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/in_in_out_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/in_in_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/in_out_out_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/in_out_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/includes.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/inplace_merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/is_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/is_heap_until.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/is_partitioned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/is_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/is_sorted.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/is_sorted_until.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/iter_swap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/iterator_operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/lexicographical_compare.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/lexicographical_compare_three_way.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/lower_bound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/make_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/make_projected.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/max.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/max_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/min.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/min_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/min_max_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/minmax.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/minmax_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/mismatch.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/move.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/move_backward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/next_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/none_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/nth_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/out_value_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/partial_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/partial_sort_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/partition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/partition_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/partition_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/pop_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/prev_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/pstl.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/push_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/radix_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_adjacent_find.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_all_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_any_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_binary_search.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_clamp.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_contains.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_contains_subrange.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_copy_backward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_copy_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_count.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_count_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_ends_with.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_equal.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_equal_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_fill.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_fill_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_find.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_find_end.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_find_first_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_find_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_find_if_not.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_find_last.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_fold.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_for_each.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_for_each_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_generate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_generate_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_includes.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_inplace_merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_is_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_is_heap_until.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_is_partitioned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_is_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_is_sorted.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_is_sorted_until.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_iterator_concept.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_lexicographical_compare.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_lower_bound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_make_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_max.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_max_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_min.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_min_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_minmax.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_minmax_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_mismatch.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_move.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_move_backward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_next_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_none_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_nth_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_partial_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_partial_sort_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_partition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_partition_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_partition_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_pop_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_prev_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_push_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_remove.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_remove_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_remove_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_remove_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_replace.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_replace_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_replace_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_replace_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_reverse.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_reverse_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_rotate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_rotate_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_sample.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_search.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_search_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_set_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_set_intersection.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_set_symmetric_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_set_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_shuffle.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_sort_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_stable_partition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_stable_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_starts_with.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_swap_ranges.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_transform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_unique.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_unique_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/ranges_upper_bound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/remove.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/remove_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/remove_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/remove_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/replace.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/replace_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/replace_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/replace_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/reverse.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/reverse_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/rotate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/rotate_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/sample.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/search.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/search_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/set_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/set_intersection.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/set_symmetric_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/set_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/shift_left.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/shift_right.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/shuffle.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/sift_down.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/simd_utils.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/sort_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/specialized_algorithms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/stable_partition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/stable_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/swap_ranges.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/three_way_comp_ref_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/transform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/uniform_random_bit_generator_adaptor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/unique.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/unique_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/unwrap_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/unwrap_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__algorithm/upper_bound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__assert" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__assertion_handler" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/aliases.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_flag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_init.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_lock_free.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_sync.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_sync_timed.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/atomic_waitable_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/check_memory_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/contention_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/fence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/floating_point_helper.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/is_always_lock_free.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/kill_dependency.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/memory_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/support.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/support/c11.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/support/gcc.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__atomic/to_gcc_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/bit_cast.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/bit_ceil.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/bit_floor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/bit_log2.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/bit_width.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/blsr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/byteswap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/countl.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/countr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/endian.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/has_single_bit.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/invert_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/popcount.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit/rotate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__bit_reference" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/chars_format.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/from_chars_floating_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/from_chars_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/from_chars_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/tables.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/to_chars.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/to_chars_base_10.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/to_chars_floating_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/to_chars_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/to_chars_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__charconv/traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/calendar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/concepts.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/convert_to_timespec.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/convert_to_tm.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/day.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/duration.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/exception.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/file_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/formatter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/gps_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/hh_mm_ss.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/high_resolution_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/is_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/leap_second.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/literals.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/local_info.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/month.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/month_weekday.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/monthday.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/ostream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/parser_std_format_spec.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/statically_widen.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/steady_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/sys_info.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/system_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/tai_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/time_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/time_zone.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/time_zone_link.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/tzdb.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/tzdb_list.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/utc_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/weekday.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/year.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/year_month.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/year_month_day.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/year_month_weekday.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__chrono/zoned_time.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/common_comparison_category.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/compare_partial_order_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/compare_strong_order_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/compare_three_way.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/compare_three_way_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/compare_weak_order_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/is_eq.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/ordering.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/partial_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/strong_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/synth_three_way.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/three_way_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__compare/weak_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/arithmetic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/boolean_testable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/class_or_enum.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/common_reference_with.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/common_with.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/comparison_common_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/convertible_to.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/copyable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/derived_from.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/different_from.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/equality_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/invocable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/movable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/predicate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/regular.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/relation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/same_as.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/semiregular.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/swappable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__concepts/totally_ordered.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__condition_variable/condition_variable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__config" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__config_site" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/abi.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/availability.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/compiler.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/experimental.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/hardening.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/language.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__configuration/platform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__coroutine/coroutine_handle.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__coroutine/coroutine_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__coroutine/noop_coroutine_handle.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__coroutine/trivial_awaitables.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cstddef/byte.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cstddef/max_align_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cstddef/nullptr_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cstddef/ptrdiff_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cstddef/size_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/adjacent_find.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/all_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/any_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/binary_search.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/comp.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/comp_ref_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/copy_backward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/copy_move_common.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/copy_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/count.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/count_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/equal.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/equal_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/fill.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/fill_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/find.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/find_end.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/find_first_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/find_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/find_if_not.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/find_segment_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/for_each.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/for_each_segment.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/generate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/generate_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/half_positive.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/includes.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/inplace_merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/is_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/is_heap_until.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/is_partitioned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/is_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/is_sorted.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/is_sorted_until.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/iter_swap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/iterator_operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/lexicographical_compare.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/lower_bound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/make_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/make_projected.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/max.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/max_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/min.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/min_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/minmax.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/minmax_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/mismatch.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/move.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/move_backward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/next_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/none_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/nth_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/partial_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/partial_sort_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/partition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/partition_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/partition_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/pop_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/prev_permutation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/push_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/remove.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/remove_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/remove_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/remove_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/replace.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/replace_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/replace_copy_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/replace_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/reverse.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/reverse_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/rotate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/rotate_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/search.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/search_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/set_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/set_intersection.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/set_symmetric_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/set_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/shuffle.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/sift_down.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/simd_utils.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/sort_heap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/stable_partition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/stable_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/swap_ranges.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/three_way_comp_ref_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/transform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/uniform_random_bit_generator_adaptor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/unique.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/unique_copy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/unwrap_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/unwrap_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__algorithm/upper_bound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__assert" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/aliases.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/atomic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/atomic_base.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/atomic_flag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/atomic_init.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/atomic_lock_free.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/atomic_sync.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/check_memory_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/contention_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/cxx_atomic_impl.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/fence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/is_always_lock_free.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/kill_dependency.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/memory_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__atomic/to_gcc_order.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit/blsr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit/countl.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit/countr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit/invert_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit/popcount.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit/rotate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__bit_reference" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__chrono/convert_to_timespec.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__chrono/duration.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__chrono/high_resolution_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__chrono/steady_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__chrono/system_clock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__chrono/time_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__condition_variable/condition_variable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__config" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__configuration/abi.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__configuration/availability.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__configuration/compiler.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__configuration/config_site_shim.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__configuration/language.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__configuration/platform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__debug_utils/randomize_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__debug_utils/sanitizers.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__debug_utils/strict_weak_ordering_check.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__exception/exception.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__exception/exception_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__exception/nested_exception.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__exception/operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__exception/terminate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/binary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/binary_negate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/bind.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/binder1st.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/binder2nd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/hash.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/identity.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/mem_fn.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/mem_fun_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/pointer_to_binary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/pointer_to_unary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/reference_wrapper.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/unary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/unary_negate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__functional/weak_result_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/array.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/bit_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/complex.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/deque.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/fstream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/functional.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/ios.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/istream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/memory.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/ostream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/pair.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/queue.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/sstream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/stack.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/streambuf.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/string.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/string_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/tuple.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__fwd/vector.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__hash_table" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__ios/fpos.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/access.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/advance.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/aliasing_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/back_insert_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/bounded_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/distance.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/erase_if_container.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/front_insert_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/insert_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/istream_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/istreambuf_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/iterator_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/move_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/next.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/ostream_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/ostreambuf_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/prev.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/reverse_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/segmented_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__iterator/wrap_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/android.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/bsd_locale_defaults.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/bsd_locale_fallbacks.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/fuchsia.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/ibm.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/locale_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/musl.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/newlib.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/openbsd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/win32.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/abs.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/copysign.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/error_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/exponential_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/fdim.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/fma.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/gamma.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/hyperbolic_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/hypot.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/inverse_hyperbolic_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/inverse_trigonometric_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/logarithms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/min_max.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/modulo.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/remainder.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/roots.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/rounding_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__math/trigonometric_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__mbstate_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/addressof.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/align.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/aligned_alloc.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/allocate_at_least.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/allocation_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/allocator_arg_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/allocator_destructor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/allocator_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/assume_aligned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/auto_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/builtin_new_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/compressed_pair.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/construct_at.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/destruct_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/pointer_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/raw_storage_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/shared_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/swap_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/temp_value.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/temporary_buffer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/uninitialized_algorithms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/unique_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/uses_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__memory/voidify.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__mutex/lock_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__mutex/mutex.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__mutex/once_flag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__mutex/tag_types.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__mutex/unique_lock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__numeric/accumulate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__numeric/adjacent_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__numeric/inner_product.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__numeric/iota.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__numeric/partial_sum.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__ostream/basic_ostream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/bernoulli_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/binomial_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/cauchy_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/chi_squared_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/clamp_to_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/default_random_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/discard_block_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/discrete_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/exponential_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/extreme_value_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/fisher_f_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/gamma_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/generate_canonical.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/geometric_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/independent_bits_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/is_seed_sequence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/is_valid.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/knuth_b.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/linear_congruential_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/log2.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/lognormal_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/mersenne_twister_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/negative_binomial_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/normal_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/piecewise_constant_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/piecewise_linear_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/poisson_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/random_device.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/ranlux.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/seed_seq.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/shuffle_order_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/student_t_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/subtract_with_carry_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/uniform_int_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/uniform_real_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__random/weibull_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__split_buffer" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__std_clang_module" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__std_mbstate_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__string/char_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__string/constexpr_c_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__string/extern_template_lists.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__support/ibm/gettod_zos.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__support/ibm/locale_mgmt_zos.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__support/ibm/nanosleep.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__support/xlocale/__nop_locale_mgmt.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__support/xlocale/__posix_l_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__support/xlocale/__strtonum_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__system_error/errc.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__system_error/error_category.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__system_error/error_code.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__system_error/error_condition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__system_error/system_error.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/id.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/poll_with_backoff.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/support.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/support/c11.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/support/external.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/support/pthread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/support/windows.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/this_thread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/thread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__thread/timed_backoff_policy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tree" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/find_index.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/make_tuple_types.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/sfinae_helpers.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_indices.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_like.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_like_ext.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_like_no_subrange.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_size.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__tuple/tuple_types.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/add_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/add_cv.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/add_lvalue_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/add_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/add_rvalue_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/add_volatile.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/aligned_storage.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/aligned_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/alignment_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/can_extract_key.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/common_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/conditional.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/conjunction.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/copy_cv.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/copy_cvref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/datasizeof.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/decay.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/dependent_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/desugars_to.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/disjunction.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/enable_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/extent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/has_virtual_destructor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/integral_constant.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/invoke.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_abstract.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_always_bitcastable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_arithmetic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_array.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_base_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_bounded_array.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_callable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_char_like_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_class.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_compound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_constant_evaluated.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_convertible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_core_convertible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_empty.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_enum.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_equality_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_execution_policy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_final.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_floating_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_fundamental.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_implicitly_default_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_literal_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_member_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_nothrow_assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_nothrow_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_nothrow_destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_null_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_object.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_pod.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_polymorphic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_primary_template.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_reference_wrapper.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_referenceable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_same.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_scalar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_signed.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_signed_integer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_specialization.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_standard_layout.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_swappable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivial.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_copyable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_lexicographically_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_relocatable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_unbounded_array.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_unsigned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_unsigned_integer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_valid_expansion.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_void.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/is_volatile.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/lazy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/make_32_64_or_128_bit.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/make_const_lvalue_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/make_signed.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/make_unsigned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/maybe_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/nat.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/negation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/noexcept_move_assign_container.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/promote.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/rank.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_all_extents.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_const_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_cv.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_cvref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_extent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/remove_volatile.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/result_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/strip_signature.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/type_identity.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/type_list.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/underlying_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/unwrap_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__type_traits/void_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__undef_macros" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/as_lvalue.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/auto_cast.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/convert_to_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/declval.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/empty.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/exception_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/forward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/integer_sequence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/is_pointer_in_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/is_valid_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/move.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/no_destroy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/pair.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/piecewise_construct.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/priority_tag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/private_constructor_tag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/rel_ops.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/small_buffer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/swap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__utility/unreachable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__variant/monostate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__verbose_abort" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/__verbose_trap" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/algorithm" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/array" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/atomic" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/bitset" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cassert" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ccomplex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cctype" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cerrno" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cfenv" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cfloat" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/chrono" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cinttypes" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ciso646" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/climits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/clocale" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cmath" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/codecvt" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/complex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/condition_variable" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/csetjmp" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/csignal" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstdarg" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstdbool" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstddef" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstdint" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstdio" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstdlib" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cstring" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ctgmath" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ctime" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cuchar" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cwchar" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/cwctype" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/deque" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/exception" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/experimental/__config" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/experimental/utility" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ext/__hash" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ext/hash_map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ext/hash_set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/forward_list" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/fstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/functional" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/future" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/iomanip" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ios" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/iosfwd" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/iostream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/istream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/iterator" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/limits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/list" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/locale" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/locale.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/math.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/memory" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/module.modulemap" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/mutex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/new" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/numeric" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ostream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/queue" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/random" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/ratio" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/regex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/sstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/stack" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/stdatomic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/stdexcept" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/stdint.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/stdlib.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/streambuf" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/string" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/string.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/string_view" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/strstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/system_error" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/thread" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/type_traits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/typeindex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/typeinfo" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/uchar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/unordered_map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/unordered_set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/utility" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/valarray" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/vector" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/version" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxx03/wchar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__cxxabi_config.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__debug_utils/randomize_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__debug_utils/sanitizers.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__debug_utils/strict_weak_ordering_check.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__exception/exception.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__exception/exception_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__exception/nested_exception.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__exception/operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__exception/terminate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__expected/bad_expected_access.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__expected/expected.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__expected/unexpect.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__expected/unexpected.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/copy_options.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/directory_entry.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/directory_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/directory_options.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/file_status.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/file_time_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/file_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/filesystem_error.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/path.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/path_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/perm_options.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/perms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/recursive_directory_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/space_info.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__filesystem/u8path.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_map/flat_map.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_map/flat_multimap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_map/key_value_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_map/sorted_equivalent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_map/sorted_unique.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_map/utils.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_set/flat_multiset.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_set/flat_set.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_set/ra_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__flat_set/utils.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/buffer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/concepts.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/container_adaptor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/enable_insertable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/escaped_output_table.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/extended_grapheme_cluster_table.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/fmt_pair_like.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_arg.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_arg_store.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_args.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_context.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_error.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_parse_context.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_string.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/format_to_n_result.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_bool.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_char.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_floating_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_integer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_output.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_string.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/formatter_tuple.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/indic_conjunct_break_table.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/parser_std_format_spec.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/range_default_formatter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/range_format.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/range_formatter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/unicode.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/width_estimation_table.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__format/write_escaped.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/binary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/binary_negate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/bind.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/bind_back.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/bind_front.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/binder1st.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/binder2nd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/boyer_moore_searcher.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/compose.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/default_searcher.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/hash.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/identity.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/invoke.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/is_transparent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/mem_fn.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/mem_fun_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/not_fn.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/perfect_forward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/pointer_to_binary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/pointer_to_unary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/ranges_operations.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/reference_wrapper.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/unary_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/unary_negate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__functional/weak_result_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/array.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/bit_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/byte.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/complex.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/deque.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/format.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/fstream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/functional.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/get.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/ios.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/istream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/mdspan.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/memory.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/memory_resource.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/ostream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/pair.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/queue.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/span.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/sstream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/stack.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/streambuf.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/string.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/string_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/subrange.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/tuple.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/variant.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__fwd/vector.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__hash_table" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ios/fpos.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/access.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/advance.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/aliasing_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/back_insert_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/bounded_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/common_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/concepts.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/counted_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/cpp17_iterator_concepts.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/data.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/default_sentinel.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/distance.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/empty.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/erase_if_container.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/front_insert_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/incrementable_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/indirectly_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/insert_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/istream_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/istreambuf_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/iter_move.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/iter_swap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/iterator_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/iterator_with_data.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/mergeable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/move_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/move_sentinel.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/next.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/ostream_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/ostreambuf_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/permutable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/prev.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/product_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/projected.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/ranges_iterator_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/readable_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/reverse_access.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/reverse_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/segmented_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/size.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/sortable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/static_bounded_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/unreachable_sentinel.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__iterator/wrap_iter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/check_grouping.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/get_c_locale.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/locale_base_api.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/locale_base_api/bsd_locale_fallbacks.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/locale_base_api/ibm.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/locale_base_api/openbsd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/messages.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/money.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/num.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/pad_and_output.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/scan_keyword.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/aix.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/apple.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/bsd_like.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/freebsd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/fuchsia.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/linux.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/netbsd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/newlib.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/no_locale/characters.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/no_locale/strtonum.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/support/windows.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/time.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/wbuffer_convert.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__locale_dir/wstring_convert.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__log_hardening_failure" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/abs.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/copysign.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/error_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/exponential_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/fdim.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/fma.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/gamma.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/hyperbolic_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/hypot.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/inverse_hyperbolic_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/inverse_trigonometric_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/logarithms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/min_max.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/modulo.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/remainder.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/roots.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/rounding_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/special_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__math/trigonometric_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mbstate_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/aligned_accessor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/default_accessor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/extents.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/layout_left.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/layout_right.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/layout_stride.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mdspan/mdspan.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/addressof.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/align.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/allocate_at_least.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/allocation_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/allocator_arg_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/allocator_destructor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/allocator_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/array_cookie.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/assume_aligned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/auto_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/compressed_pair.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/concepts.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/construct_at.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/destroy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/destruct_n.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/inout_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/is_sufficiently_aligned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/noexcept_move_assign_container.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/out_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/pointer_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/ranges_construct_at.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/ranges_destroy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/ranges_uninitialized_algorithms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/raw_storage_iterator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/shared_count.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/shared_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/swap_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/temp_value.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/temporary_buffer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/uninitialized_algorithms.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/unique_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/unique_temporary_buffer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/uses_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory/uses_allocator_construction.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory_resource/memory_resource.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory_resource/monotonic_buffer_resource.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory_resource/polymorphic_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory_resource/pool_options.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory_resource/synchronized_pool_resource.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__memory_resource/unsynchronized_pool_resource.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mutex/lock_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mutex/mutex.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mutex/once_flag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mutex/tag_types.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__mutex/unique_lock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/align_val_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/allocate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/destroying_delete_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/exceptions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/global_new_delete.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/interference_size.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/launder.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/new_handler.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/nothrow_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__new/placement_new_delete.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__node_handle" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/accumulate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/adjacent_difference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/exclusive_scan.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/gcd_lcm.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/inclusive_scan.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/inner_product.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/iota.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/midpoint.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/partial_sum.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/pstl.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/ranges_iota.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/reduce.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/saturation_arithmetic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/transform_exclusive_scan.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/transform_inclusive_scan.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__numeric/transform_reduce.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ostream/basic_ostream.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ostream/print.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ostream/put_character_sequence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/backend.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/backend_fwd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/backends/default.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/backends/libdispatch.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/backends/serial.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/backends/std_thread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/any_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/cpu_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/fill.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/find_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/for_each.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/merge.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/stable_sort.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/transform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/cpu_algos/transform_reduce.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/dispatch.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__pstl/handle_exception.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/bernoulli_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/binomial_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/cauchy_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/chi_squared_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/clamp_to_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/default_random_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/discard_block_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/discrete_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/exponential_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/extreme_value_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/fisher_f_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/gamma_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/generate_canonical.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/geometric_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/independent_bits_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/is_seed_sequence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/is_valid.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/knuth_b.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/linear_congruential_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/log2.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/lognormal_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/mersenne_twister_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/negative_binomial_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/normal_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/piecewise_constant_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/piecewise_linear_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/poisson_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/random_device.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/ranlux.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/seed_seq.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/shuffle_order_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/student_t_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/subtract_with_carry_engine.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/uniform_int_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/uniform_random_bit_generator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/uniform_real_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__random/weibull_distribution.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/access.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/adjacent_transform_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/adjacent_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/all.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/as_rvalue_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/chunk_by_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/common_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/concepts.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/container_compatible_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/counted.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/dangling.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/data.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/drop_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/drop_while_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/elements_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/elements_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/empty.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/empty_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/enable_borrowed_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/enable_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/filter_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/from_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/iota_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/istream_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/join_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/join_with_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/lazy_split_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/movable_box.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/non_propagating_cache.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/owning_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/range_adaptor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/rbegin.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/ref_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/rend.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/repeat_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/reverse_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/single_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/size.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/split_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/subrange.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/take_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/take_while_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/to.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/transform_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/view_interface.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/views.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/zip_transform_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__ranges/zip_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__split_buffer" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__std_mbstate_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/atomic_unique_lock.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/intrusive_list_view.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/intrusive_shared_ptr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/stop_callback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/stop_source.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/stop_state.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__stop_token/stop_token.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__string/char_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__string/constexpr_c_functions.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__string/extern_template_lists.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__support/ibm/gettod_zos.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__support/ibm/locale_mgmt_zos.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__support/ibm/nanosleep.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__support/xlocale/__nop_locale_mgmt.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__support/xlocale/__posix_l_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__support/xlocale/__strtonum_fallback.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__system_error/errc.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__system_error/error_category.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__system_error/error_code.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__system_error/error_condition.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__system_error/system_error.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__system_error/throw_system_error.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/formatter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/id.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/jthread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/poll_with_backoff.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/support.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/support/c11.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/support/external.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/support/pthread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/support/windows.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/this_thread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/thread.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__thread/timed_backoff_policy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tree" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/find_index.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/ignore.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/sfinae_helpers.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/tuple_element.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/tuple_like.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/tuple_like_no_subrange.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/tuple_size.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__tuple/tuple_transform.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/add_cv_quals.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/add_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/add_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/aligned_storage.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/aligned_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/alignment_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/common_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/common_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/conditional.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/conjunction.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/container_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/copy_cv.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/copy_cvref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/datasizeof.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/decay.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/dependent_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/desugars_to.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/detected_or.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/disjunction.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/enable_if.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/extent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/has_unique_object_representation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/has_virtual_destructor.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/integer_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/integral_constant.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/invoke.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_abstract.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_aggregate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_allocator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_always_bitcastable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_arithmetic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_array.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_base_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_callable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_char_like_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_class.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_compound.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_constant_evaluated.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_convertible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_core_convertible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_empty.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_enum.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_equality_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_execution_policy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_final.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_floating_point.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_function.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_fundamental.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_generic_transparent_comparator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_implicit_lifetime.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_implicitly_default_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_literal_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_member_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_nothrow_assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_nothrow_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_nothrow_destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_null_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_object.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_pod.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_polymorphic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_primary_template.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_reference_wrapper.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_referenceable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_same.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_scalar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_signed.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_specialization.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_standard_layout.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_swappable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivial.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivially_assignable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivially_constructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivially_copyable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivially_destructible.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivially_lexicographically_comparable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_trivially_relocatable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_union.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_unqualified.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_unsigned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_valid_expansion.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_void.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_volatile.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/is_within_lifetime.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/lazy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/make_32_64_or_128_bit.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/make_const_lvalue_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/make_signed.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/make_transparent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/make_unsigned.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/maybe_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/nat.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/negation.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/promote.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/rank.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/reference_constructs_from_temporary.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/reference_converts_from_temporary.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_all_extents.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_const_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_cv.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_cvref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_extent.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_pointer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/remove_volatile.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/result_of.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/strip_signature.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/type_identity.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/type_list.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/underlying_type.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/unwrap_ref.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__type_traits/void_t.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__undef_macros" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/as_const.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/as_lvalue.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/auto_cast.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/cmp.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/convert_to_integral.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/declval.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/default_three_way_comparator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/element_count.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/empty.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/exception_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/exchange.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/forward.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/forward_like.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/in_place.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/integer_sequence.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/is_pointer_in_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/is_valid_range.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/lazy_synth_three_way_comparator.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/move.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/no_destroy.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/pair.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/piecewise_construct.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/priority_tag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/private_constructor_tag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/rel_ops.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/scope_guard.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/small_buffer.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/swap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/to_underlying.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/try_key_extraction.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__utility/unreachable.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__variant/monostate.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/comparison.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/container_traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/erase.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/pmr.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/swap.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/vector.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/vector_bool.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__vector/vector_bool_formatter.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__verbose_abort" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/__verbose_trap" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/algorithm" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/any" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/array" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/atomic" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/barrier" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/bit" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/bitset" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cassert" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ccomplex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cctype" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cerrno" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cfenv" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cfloat" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/charconv" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/chrono" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cinttypes" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ciso646" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/climits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/clocale" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cmath" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/codecvt" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/compare" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/complex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/complex.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/concepts" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/condition_variable" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/coroutine" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/csetjmp" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/csignal" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstdalign" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstdarg" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstdbool" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstddef" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstdint" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstdio" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstdlib" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cstring" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ctgmath" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ctime" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ctype.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cuchar" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cwchar" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cwctype" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/cxxabi.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/deque" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/errno.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/exception" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/execution" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/expected" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/aligned_tag.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/declaration.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/reference.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/scalar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/simd.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/simd_mask.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/traits.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/utility.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/__simd/vec_ext.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/iterator" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/memory" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/propagate_const" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/simd" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/type_traits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/experimental/utility" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ext/__hash" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ext/hash_map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ext/hash_set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/fenv.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/filesystem" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/flat_map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/flat_set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/float.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/format" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/forward_list" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/fstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/functional" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/future" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/initializer_list" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/inttypes.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/iomanip" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ios" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/iosfwd" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/iostream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/istream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/iterator" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/latch" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/libcxx.imp" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/limits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/list" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/locale" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/math.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/mdspan" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/memory" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/memory_resource" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/module.modulemap" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/mutex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/new" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/numbers" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/numeric" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/optional" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ostream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/print" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/queue" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/random" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ranges" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/ratio" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/regex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/scoped_allocator" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/semaphore" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/shared_mutex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/source_location" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/span" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/sstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stack" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stdatomic.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stddef.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stdexcept" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stdio.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stdlib.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/stop_token" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/streambuf" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/string" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/string.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/string_view" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/strstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/syncstream" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/system_error" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/tgmath.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/thread" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/tuple" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/type_traits" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/typeindex" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/typeinfo" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/uchar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/unordered_map" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/unordered_set" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/utility" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/valarray" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/variant" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/vector" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/version" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/wchar.h" - textual header "/nix/store/3vsjx6pixhgk4kl69yhwbjrm9khfr7zp-libcxx-22.1.0-rc3-dev/include/c++/v1/wctype.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_builtin_vars.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_cmath.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_complex_builtins.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_device_functions.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_intrinsics.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_libdevice_declares.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_math.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_math_forward_declares.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_runtime_wrapper.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_cuda_texture_intrinsics.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_hip_cmath.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_hip_libdevice_declares.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_hip_math.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_hip_runtime_wrapper.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_hip_stdlib.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__clang_spirv_builtins.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__float_float.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__float_header_macro.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__float_infinity_nan.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stdarg___gnuc_va_list.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stdarg___va_copy.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stdarg_header_macro.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stdarg_va_arg.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stdarg_va_copy.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stdarg_va_list.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_header_macro.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_max_align_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_null.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_nullptr_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_offsetof.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_ptrdiff_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_rsize_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_size_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_unreachable.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_wchar_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__stddef_wint_t.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__wmmintrin_aes.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/__wmmintrin_pclmul.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/adcintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/adxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/altivec.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amdgpuintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ammintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amo.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxavx512intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxcomplexintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxfp16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxfp8intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxmovrsintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/amxtf32intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/andes_vector.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm64intr.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_acle.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_bf16.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_cde.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_cmse.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_fp16.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_mve.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_neon.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_neon_sve_bridge.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_sme.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_sve.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/arm_vector_types.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/armintr.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2_512bf16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2_512convertintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2_512minmaxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2_512niintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2_512satcvtdsintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2_512satcvtintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2bf16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2convertintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2copyintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2minmaxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2niintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2satcvtdsintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx10_2satcvtintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx2intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512bf16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512bitalgintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512bwintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512cdintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512dqintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512fintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512fp16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512ifmaintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512ifmavlintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vbmi2intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vbmiintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vbmivlintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlbf16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlbitalgintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlbwintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlcdintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vldqintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlfp16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlvbmi2intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlvnniintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vlvp2intersectintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vnniintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vp2intersectintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vpopcntdqintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avx512vpopcntdqvlintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avxifmaintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avxneconvertintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avxvnniint16intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avxvnniint8intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/avxvnniintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/bmi2intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/bmiintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/builtins.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cet.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cetintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cldemoteintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/clflushoptintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/clwbintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/clzerointrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cmpccxaddintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cpuid.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/crc32intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/__utility/declval.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/algorithm" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/bits/basic_string.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/bits/basic_string.tcc" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/bits/c++config.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/bits/shared_ptr_base.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/cmath" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/complex" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/cuda_wrappers/new" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/emmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/enqcmdintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/f16cintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/float.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/fma4intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/fmaintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/fxsrintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/gfniintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/gpuintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/hexagon_circ_brev_intrinsics.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/hexagon_protos.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/hexagon_types.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/hresetintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/htmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/htmxlintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/hvx_hexagon_protos.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ia32intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/immintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/intrin0.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/inttypes.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/invpcidintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/iso646.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/keylockerintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/larchintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/lasxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/limits.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/assert.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/ctype.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/inttypes.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/stdio.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/stdlib.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/string.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_libc_wrappers/time.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_offload_wrappers/__llvm_offload.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_offload_wrappers/__llvm_offload_device.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/llvm_offload_wrappers/__llvm_offload_host.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/lsxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/lwpintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/lzcntintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/mm3dnow.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/mm_malloc.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/mmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/module.modulemap" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/movdirintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/movrs_avx10_2_512intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/movrs_avx10_2intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/movrsintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/msa.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/mwaitxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/nmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/nvptxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/opencl-c-base.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/opencl-c.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/__clang_openmp_device_functions.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/cmath" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/complex" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/complex.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/complex_cmath.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/math.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/openmp_wrappers/new" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/pconfigintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/pkuintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/pmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/popcntintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/bmi2intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/bmiintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/emmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/immintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/mm_malloc.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/mmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/nmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/pmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/smmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/tmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/x86gprintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/x86intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ppc_wrappers/xmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/prfchiintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/prfchwintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ptrauth.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/ptwriteintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/raointintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/rdpruintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/rdseedintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_bitmanip.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_corev_alu.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_crypto.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_mips.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_nds.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_ntlh.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/riscv_vector.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/rtmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/s390intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/serializeintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/sgxintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/sha512intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/shaintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/sifive_vector.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/sm3intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/sm4evexintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/sm4intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/smmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/spirvintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdalign.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdarg.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdatomic.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdbool.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdckdint.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdcountof.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stddef.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stddefer.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdint.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/stdnoreturn.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/tbmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/tgmath.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/tmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/tsxldtrkintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/uintrintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/unwind.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/usermsrintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/vadefs.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/vaesintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/varargs.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/vecintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/velintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/velintrin_approx.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/velintrin_gen.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/vpclmulqdqintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/waitpkgintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/wasm_simd128.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/wbnoinvdintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/wmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/x86gprintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/x86intrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xmmintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xopintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xsavecintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xsaveintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xsaveoptintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xsavesintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/xtestintrin.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/yvals_core.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/include/zos_wrappers/builtins.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/a.out.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/aio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/aliases.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/alloca.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/argp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/argz.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/arpa/ftp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/arpa/inet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/arpa/nameser.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/arpa/nameser_compat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/arpa/telnet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/arpa/tftp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/auxvec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/bitsperlong.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/bpf_perf_event.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/errno-base.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/errno.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/fcntl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/hugetlb_encode.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/int-l64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/int-ll64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/ioctls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/ipcbuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/kvm_para.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/mman-common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/mman.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/msgbuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/param.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/poll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/posix_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/resource.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/sembuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/setup.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/shmbuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/siginfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/signal-defs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/signal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/sockios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/stat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/statfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/swab.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/termbits-common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/termbits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/termios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/ucontext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm-generic/unistd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/a.out.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/amd_hsmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/auxvec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/bitsperlong.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/boot.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/bootparam.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/bpf_perf_event.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/byteorder.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/debugreg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/e820.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/elf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/errno.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/fcntl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/hw_breakpoint.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/hwcap2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ioctls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ipcbuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ist.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/kvm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/kvm_para.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/kvm_perf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ldt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/mce.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/mman.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/msgbuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/msr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/mtrr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/param.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/perf_regs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/poll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/posix_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/posix_types_32.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/posix_types_64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/posix_types_x32.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/prctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/processor-flags.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ptrace-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ptrace.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/resource.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/sembuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/setup.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/setup_data.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/sgx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/shmbuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/sigcontext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/sigcontext32.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/siginfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/signal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/sockios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/stat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/statfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/svm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/swab.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/termbits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/termios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/ucontext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/unistd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/unistd_32.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/unistd_64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/unistd_x32.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/vm86.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/vmx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/asm/vsyscall.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/assert.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/a.out.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/argp-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/atomic_wide_counter.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/byteswap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/cloexec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/cmathcalls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/confname.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/cpu-set.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/dirent.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/dirent_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/dl_find_object.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/dlfcn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/elfclass.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/endian.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/endianness.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/environments.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/epoll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/err-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/errno.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/error-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/error.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/eventfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/fcntl-linux.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/fcntl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/fcntl2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/fenv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/floatn-common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/floatn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/flt-eval-method.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/fp-fast.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/fp-logb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/getopt_core.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/getopt_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/getopt_posix.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/hwcap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/in.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/indirect-return.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/inet-fortified-decl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/inet-fortified.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/initspin.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/inotify.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ioctl-types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ioctls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ipc-perm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ipc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ipctypes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/iscanonical.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/libc-header-start.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/libm-simd-decl-stubs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/link.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/link_lavcurrent.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/local_lim.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/locale.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/long-double.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/math-vector.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mathcalls-helper-functions.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mathcalls-macros.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mathcalls-narrow.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mathcalls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mathdef.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mman-linux.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mman-map-flags-generic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mman-shared.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mman.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mman_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/monetary-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mqueue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/mqueue2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/msq.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/netdb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/param.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/platform/features.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/platform/x86.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/poll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/poll2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/posix1_lim.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/posix2_lim.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/posix_opt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/printf-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/procfs-extra.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/procfs-id.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/procfs-prregset.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/procfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/pthread_stack_min-dynamic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/pthread_stack_min.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/pthreadtypes-arch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/pthreadtypes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ptrace-shared.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/resource.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/rseq.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sched.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/select-decl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/select.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/select2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sem.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/semaphore.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/setjmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/setjmp2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/shm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/shmlba.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sigaction.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sigcontext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sigevent-consts.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/siginfo-arch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/siginfo-consts-arch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/siginfo-consts.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/signal_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/signalfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/signum-arch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/signum-generic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sigstack.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sigstksz.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sigthread.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sockaddr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/socket-constants.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/socket2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/socket_type.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/spawn_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/ss_flags.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stab.def" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/statfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/statvfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/statx-generic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/statx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdint-intn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdint-least.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdint-uintn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdio-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdio2-decl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdio2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdio_lim.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdlib-bsearch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdlib-float.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdlib-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/stdlib.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/string_fortified.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/strings_fortified.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/struct_mutex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/struct_rwlock.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/struct_stat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/struct_stat_time64_helper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/syscall.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/syslog-decl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/syslog-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/syslog-path.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/syslog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/sysmacros.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-baud.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-c_cc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-c_cflag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-c_iflag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-c_lflag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-c_oflag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-cbaud.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-misc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-struct.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios-tcflow.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/termios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/thread-shared-types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/time.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/time64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/timerfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/timesize.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/timex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/FILE.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__FILE.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__fpos64_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__fpos_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__locale_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__mbstate_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__sigset_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/__sigval_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/clock_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/clockid_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/cookie_io_functions_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/error_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/idtype_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/locale_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/mbstate_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/res_state.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/sig_atomic_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/sigevent_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/siginfo_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/sigset_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/sigval_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/stack_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_FILE.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct___jmp_buf_tag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_iovec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_itimerspec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_msqid64_ds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_msqid64_ds_helper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_msqid_ds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_osockaddr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_rusage.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_sched_param.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_semid64_ds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_semid64_ds_helper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_semid_ds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_shmid64_ds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_shmid64_ds_helper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_shmid_ds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_sigstack.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_statx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_statx_timestamp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_timeb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_timespec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_timeval.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/struct_tm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/time_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/timer_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/types/wint_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/typesizes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/uintn-identity.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/uio-ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/uio_lim.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/unistd-decl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/unistd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/unistd_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/utmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/utmpx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/utsname.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/waitflags.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/waitstatus.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/wchar-ldbl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/wchar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/wchar2-decl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/wchar2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/wctype-wchar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/wordsize.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/bits/xopen_lim.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/byteswap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/complex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/config/kernel.release" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/cpio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ctype.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/cxl/features.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/dirent.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/dlfcn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/amdgpu_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/amdxdna_accel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/armada_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/asahi_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/drm_fourcc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/drm_mode.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/drm_sarea.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/etnaviv_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/exynos_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/habanalabs_accel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/i915_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/ivpu_accel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/lima_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/msm_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/nouveau_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/nova_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/omap_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/panfrost_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/panthor_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/pvr_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/qaic_accel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/qxl_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/radeon_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/rocket_accel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/tegra_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/v3d_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/vc4_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/vgem_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/virtgpu_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/vmwgfx_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/drm/xe_drm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/elf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/endian.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/envz.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/err.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/errno.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/error.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/execinfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fcntl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/features-time64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/features.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fenv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/finclude/math-vector-fortran.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fmtmsg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fnmatch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fpu_control.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fstab.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fts.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ftw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fwctl/cxl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fwctl/fwctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fwctl/mlx5.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/fwctl/pds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gconv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/getopt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/glob.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gnu-versions.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gnu/lib-names-64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gnu/lib-names.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gnu/libc-version.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gnu/stubs-64.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gnu/stubs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/grp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/gshadow.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/iconv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ieee754.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ifaddrs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/inttypes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/langinfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/lastlog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/libgen.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/libintl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/limits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/link.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/a.out.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/acct.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/acrn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/adb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/adfs_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/affs_hardblocks.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/agpgart.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/aio_abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/am437x-vpfe.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/amt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/android/binder.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/android/binder_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/android/binderfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/apm_bios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/arcfb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/arm_sdei.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/aspeed-lpc-ctrl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/aspeed-p2a-ctrl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/aspeed-video.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atalk.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm_eni.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm_he.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm_idt77105.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm_nicstar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm_tcp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atm_zatm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmapi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmarp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmbr2684.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmclip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmioc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmlec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmmpc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmppp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmsap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/atmsvc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/audit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/auto_dev-ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/auto_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/auto_fs4.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/auxvec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ax25.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/batadv_packet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/batman_adv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/baycom.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bcm933xx_hcs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bfs_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/binfmts.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/blk-crypto.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/blkdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/blkpg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/blktrace_api.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/blkzoned.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bpf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bpf_common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bpf_perf_event.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bpqether.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bsg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/bt-bmc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/btf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/btrfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/btrfs_tree.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/byteorder/big_endian.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/byteorder/little_endian.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cachefiles.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/caif/caif_socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/caif/if_caif.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/bcm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/error.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/gw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/isotp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/j1939.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/raw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/can/vxcan.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/capability.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/capi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cciss_defs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cciss_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ccs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cdrom.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cec-funcs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cfm_bridge.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cgroupstats.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/chio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cifs/cifs_mount.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cifs/cifs_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/close_range.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cn_proc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/coda.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/coff.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/comedi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/connector.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/const.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/coredump.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/coresight-stm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/counter.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/counter/microchip-tcb-capture.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cramfs_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cryptouser.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cuda.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cxl_mem.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cyclades.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/cycx_cfm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dcbnl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dccp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/devlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dlm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dlm_device.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dlm_plock.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dlmconstants.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dm-ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dm-log-userspace.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dma-buf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dma-heap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dns_resolver.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dpll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dqblk_xfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/audio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/ca.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/dmx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/frontend.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/net.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/osd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/version.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dvb/video.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/dw100.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/edd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/efs_fs_sb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/elf-em.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/elf-fdpic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/elf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/errno.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/errqueue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/erspan.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ethtool.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ethtool_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ethtool_netlink_generated.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/eventfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/eventpoll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/exfat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ext4.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/f2fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fadvise.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/falloc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fanotify.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fcntl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fdreg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fib_rules.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fiemap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/filter.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/firewire-cdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/firewire-constants.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fou.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fpga-dfl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fscrypt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fsi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fsl_hypervisor.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fsl_mc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fsmap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fsverity.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/fuse.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/futex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/gameport.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/gen_stats.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/genetlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/genwqe/genwqe_card.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/gfs2_ondisk.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/gpio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/gsmmux.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/gtp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/handshake.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hash_info.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hdlc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hdlc/ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hdlcdrv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hdreg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hiddev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hidraw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hpet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hsi/cs-protocol.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hsi/hsi_char.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hsr_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hw_breakpoint.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/hyperv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/i2c-dev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/i2c.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/i2o-dev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/i8k.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/icmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/icmpv6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/idxd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_addr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_addrlabel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_alg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_arcnet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_arp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_bonding.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_bridge.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_eql.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_ether.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_fc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_fddi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_hippi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_infiniband.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_link.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_ltalk.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_macsec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_packet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_phonet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_plip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_ppp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_pppol2tp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_pppox.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_slip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_team.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_tun.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_tunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_vlan.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_x25.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/if_xdp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ife.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/igmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/iio/buffer.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/iio/events.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/iio/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ila.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/in.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/in6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/in_route.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/inet_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/inotify.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/input-event-codes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/input.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/io_uring.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/io_uring/mock_file.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/io_uring/query.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ioam6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ioam6_genl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ioam6_iptunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/iommufd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ioprio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ip6_tunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ip_vs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipmi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipmi_bmc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipmi_msgdefs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipmi_ssif_bmc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipsec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipv6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ipv6_route.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/irqnr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/isdn/capicmd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/iso_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/isst_if.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ivtv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ivtvfb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/jffs2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/joystick.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kcm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kcmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kcov.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kdev_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kernel-page-flags.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kernel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kernelcapi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kexec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/keyboard.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/keyctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kfd_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kfd_sysfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kvm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/kvm_para.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/l2tp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/landlock.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/libc-compat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/limits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/lirc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/llc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/loadpin.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/lockd_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/loop.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/lp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/lsm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/lwtunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/magic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/major.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/map_to_14segment.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/map_to_7segment.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/matroxfb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/max2175.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mctp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mdio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media-bus-format.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media/amlogic/c3-isp-config.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media/raspberrypi/pisp_be_config.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media/raspberrypi/pisp_common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media/raspberrypi/pisp_fe_config.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/media/raspberrypi/pisp_fe_statistics.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mei.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mei_uuid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/membarrier.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/memfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mempolicy.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mii.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/minix_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/misc/bcm_vk.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mman.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mmc/ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mmtimer.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/module.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mount.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mpls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mpls_iptunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mptcp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mptcp_pm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mqueue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mroute.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mroute6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mrp_bridge.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/msdos_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/msg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mshv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/mtio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nbd-netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nbd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ncsi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ndctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/neighbour.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/net.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/net_dropmon.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/net_namespace.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/net_shaper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/net_tstamp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netconf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netdevice.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/ipset/ip_set.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/ipset/ip_set_bitmap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/ipset/ip_set_hash.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/ipset/ip_set_list.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_conntrack_common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_conntrack_ftp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_conntrack_sctp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_conntrack_tcp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_conntrack_tuple_common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_log.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_nat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_synproxy.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_tables.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nf_tables_compat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_acct.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_compat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_conntrack.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_cthelper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_cttimeout.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_hook.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_log.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_osf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/nfnetlink_queue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/x_tables.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_AUDIT.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_CHECKSUM.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_CLASSIFY.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_CONNMARK.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_CONNSECMARK.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_CT.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_DSCP.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_HMARK.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_IDLETIMER.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_LED.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_LOG.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_MARK.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_NFLOG.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_NFQUEUE.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_RATEEST.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_SECMARK.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_SYNPROXY.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_TCPMSS.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_TCPOPTSTRIP.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_TEE.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_TPROXY.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_addrtype.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_bpf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_cgroup.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_cluster.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_comment.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_connbytes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_connlabel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_connlimit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_connmark.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_conntrack.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_cpu.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_dccp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_devgroup.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_dscp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_ecn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_esp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_hashlimit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_helper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_ipcomp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_iprange.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_ipvs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_l2tp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_length.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_limit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_mac.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_mark.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_multiport.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_nfacct.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_osf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_owner.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_physdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_pkttype.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_policy.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_quota.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_rateest.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_realm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_recent.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_rpfilter.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_sctp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_set.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_state.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_statistic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_string.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_tcpmss.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_tcpudp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_time.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter/xt_u32.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_arp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_arp/arp_tables.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_arp/arpt_mangle.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_802_3.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_among.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_arp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_arpreply.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_ip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_ip6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_limit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_log.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_mark_m.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_mark_t.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_nat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_nflog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_pkttype.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_redirect.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_stp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebt_vlan.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_bridge/ebtables.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ip_tables.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_ECN.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_LOG.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_REJECT.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_TTL.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_ah.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_ecn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv4/ipt_ttl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6_tables.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_HL.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_LOG.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_NPT.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_REJECT.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_ah.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_frag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_hl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_ipv6header.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_mh.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_opts.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_rt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netfilter_ipv6/ip6t_srh.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netlink_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/netrom.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nexthop.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs3.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs4.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs4_mount.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs_idmap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfs_mount.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfsacl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfsd/cld.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfsd/debug.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfsd/export.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfsd/stats.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nfsd_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nilfs2_api.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nilfs2_ondisk.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nitro_enclaves.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nl80211-vnd-intel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nl80211.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/npcm-video.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nsfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nsm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ntsync.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nubus.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nvme_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/nvram.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/omap3isp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/omapfb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/oom.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/openat2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/openvswitch.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ovpn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/packet_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/papr_pdsm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/param.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/parport.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/patchkey.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pci.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pci_regs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pcitest.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/perf_event.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/personality.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pfkeyv2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pfrut.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/phantom.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/phonet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pidfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pkt_cls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pkt_sched.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pktcdvd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pmu.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/poll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/posix_acl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/posix_acl_xattr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/posix_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ppdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ppp-comp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ppp-ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ppp_defs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pps.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pps_gen.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/prctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/psample.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/psci.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/psp-dbc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/psp-sev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/psp-sfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/psp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ptp_clock.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ptrace.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/pwm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/qemu_fw_cfg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/qnx4_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/qnxtypes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/qrtr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/quota.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/radeonfb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/raid/md_p.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/raid/md_u.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/random.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/reboot.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/remoteproc_cdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/resource.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rfkill.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rio_cm_cdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rio_mport_cdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rkisp1-config.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/romfs_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rose.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/route.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rpl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rpl_iptunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rpmsg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rpmsg_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rseq.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rtc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rtnetlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/rxrpc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/scc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sched.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sched/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/scif_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/screen_info.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sctp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/seccomp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/securebits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sed-opal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/seg6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/seg6_genl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/seg6_hmac.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/seg6_iptunnel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/seg6_local.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/selinux_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sem.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/serial.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/serial_core.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/serial_reg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/serio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sev-guest.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/shm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/signal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/signalfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/smc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/smc_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/smiapp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/snmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sock_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sockios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sonet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sonypi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sound.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/soundcard.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/spi/spi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/spi/spidev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/stat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/stddef.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/stm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/string.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sunrpc/debug.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/surface_aggregator/cdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/surface_aggregator/dtx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/suspend_ioctls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/swab.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/switchtec_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sync_file.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/synclink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sysctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/sysinfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/target_core_user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/taskstats.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_bpf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_connmark.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_csum.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_ct.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_ctinfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_defact.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_gact.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_gate.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_ife.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_mirred.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_mpls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_nat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_pedit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_sample.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_skbedit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_skbmod.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_tunnel_key.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_act/tc_vlan.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_ematch/tc_em_cmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_ematch/tc_em_ipt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_ematch/tc_em_meta.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_ematch/tc_em_nbyte.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tc_ematch/tc_em_text.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tcp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tcp_metrics.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tdx-guest.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tee.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/termios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/thermal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/thp7312.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/time.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/time_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/timerfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/times.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/timex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tiocl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tipc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tipc_config.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tipc_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tipc_sockets_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/toshiba.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tps6594_pfsm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/trace_mmap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tty.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/tty_flags.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ublk_cmd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/udf_fs_i.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/udmabuf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/udp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/uhid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/uinput.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/uio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/uleds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/ultrasound.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/um_timetravel.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/un.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/unistd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/unix_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/audio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/cdc-wdm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/cdc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/ch11.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/ch9.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/charger.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/functionfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/g_hid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/g_printer.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/g_uvc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/gadgetfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/midi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/raw_gadget.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/tmc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usb/video.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usbdevice_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/usbip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/user_events.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/userfaultfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/userio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/utime.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/utsname.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/uuid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/uvcvideo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/v4l2-common.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/v4l2-controls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/v4l2-dv-timings.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/v4l2-mediabus.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/v4l2-subdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vbox_err.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vbox_vmmdev_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vboxguest.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vdpa.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vduse.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/version.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vesa.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/veth.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vfio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vfio_ccw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vfio_zdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vhost.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vhost_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/videodev2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_9p.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_balloon.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_blk.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_bt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_config.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_console.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_crypto.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_fs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_gpio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_gpu.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_i2c.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_ids.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_input.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_iommu.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_mem.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_mmio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_net.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_pci.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_pcidev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_pmem.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_ring.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_rng.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_rtc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_scmi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_scsi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_snd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_spi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/virtio_vsock.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vm_sockets.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vm_sockets_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vmclock-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vmcore.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vsockmon.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/vtpm_proxy.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/wait.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/watch_queue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/watchdog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/wireguard.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/wireless.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/wmi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/wwan.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/x25.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/xattr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/xdp_diag.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/xfrm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/xilinx-v4l2-controls.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/zorro.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/linux/zorro_ids.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/locale.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/malloc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/math.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mcheck.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/memory.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/amd-apml.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/fastrpc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/mrvl_cn10k_dpi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/ocxl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/pvpanic.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/uacce/hisi_qm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/uacce/uacce.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/misc/xilinx_sdfec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mntent.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/monetary.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mqueue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mtd/inftl-user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mtd/mtd-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mtd/mtd-user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mtd/nftl-user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/mtd/ubi-user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/ethernet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/if.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/if_arp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/if_packet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/if_ppp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/if_shaper.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/if_slip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/ppp-comp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/ppp_defs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/net/route.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netash/ash.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netatalk/at.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netax25/ax25.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netdb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/neteconet/ec.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/ether.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/icmp6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/if_ether.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/if_fddi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/if_tr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/igmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/in.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/in_systm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/ip.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/ip6.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/ip_icmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/tcp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netinet/udp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netipx/ipx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netiucv/iucv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netpacket/packet.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netrom/netrom.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/netrose/rose.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/nfs/nfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/nl_types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/nss.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/obstack.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/paths.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/poll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/printf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/proc_service.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/protocols/routed.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/protocols/rwhod.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/protocols/talkd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/protocols/timed.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/pthread.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/pty.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/pwd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/bnxt_re-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/cxgb4-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/efa-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/erdma-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/hfi/hfi1_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/hfi/hfi1_user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/hns-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ib_user_ioctl_cmds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ib_user_ioctl_verbs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ib_user_mad.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ib_user_sa.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ib_user_verbs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ionic-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/irdma-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/mana-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/mlx4-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/mlx5-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/mlx5_user_ioctl_cmds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/mlx5_user_ioctl_verbs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/mthca-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/ocrdma-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/qedr-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/rdma_netlink.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/rdma_user_cm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/rdma_user_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/rdma_user_ioctl_cmds.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/rdma_user_rxe.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/rvt-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/siw-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rdma/vmw_pvrdma-abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/re_comp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/regex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/regexp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/regulator/regulator.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/resolv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/rpc/netdb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sched.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/scsi/scsi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/scsi/scsi_ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/scsi/sg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/search.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/semaphore.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/setjmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sgtty.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/shadow.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/signal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/asequencer.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/asoc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/asound.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/asound_fm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/compress_offload.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/compress_params.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/emu10k1.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/fcp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/firewire.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/hdsp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/hdspm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/intel/avs/tokens.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/sb16_csp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/scarlett2.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/sfnt_info.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/skl-tplg-interface.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/snd_ar_tokens.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/snd_sst_tokens.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/sof/abi.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/sof/fw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/sof/header.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/sof/tokens.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/tlv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sound/usb_stream.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/spawn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stab.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stdbit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stdc-predef.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stdint.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stdio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stdio_ext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/stdlib.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/string.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/strings.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/acct.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/auxv.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/bitypes.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/cdefs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/debugreg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/dir.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/elf.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/epoll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/errno.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/eventfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/fanotify.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/fcntl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/file.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/fsuid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/gmon.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/gmon_out.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/inotify.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/io.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/ioctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/ipc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/kd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/klog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/mman.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/mount.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/msg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/mtio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/param.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/pci.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/perm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/personality.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/pidfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/platform/x86.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/poll.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/prctl.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/procfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/profil.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/ptrace.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/queue.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/quota.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/random.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/raw.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/reboot.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/reg.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/resource.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/rseq.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/select.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/sem.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/sendfile.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/shm.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/signal.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/signalfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/single_threaded.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/socket.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/socketvar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/soundcard.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/stat.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/statfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/statvfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/swap.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/syscall.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/sysinfo.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/syslog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/sysmacros.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/termios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/time.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/timeb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/timerfd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/times.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/timex.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/ttychars.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/ttydefaults.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/types.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/ucontext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/uio.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/un.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/unistd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/user.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/utsname.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/vfs.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/vlimit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/vm86.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/vt.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/wait.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sys/xattr.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/syscall.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/sysexits.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/syslog.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/tar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/termios.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/tgmath.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/thread_db.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/threads.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/time.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ttyent.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/uchar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ucontext.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/ulimit.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/unistd.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/utime.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/utmp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/utmpx.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/values.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/video/edid.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/video/sisfb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/video/uvesafb.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/wait.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/wchar.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/wctype.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/wordexp.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/xen/evtchn.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/xen/gntalloc.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/xen/gntdev.h" + textual header "/nix/store/q5wv2ldpcv5w8yb2wmsngsygvlxb73fk-glibc-2.42-67-dev/include/xen/privcmd.h" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share/asan_ignorelist.txt" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share/cfi_ignorelist.txt" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share/dfsan_abilist.txt" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share/hwasan_ignorelist.txt" + textual header "/nix/store/h590aa9zij6n1kimlnj9fyh038rmj396-clang-wrapper-22.1.8/resource-root/share/msan_ignorelist.txt" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/adjacent_find.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/all_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/any_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/binary_search.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/clamp.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/comp.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/comp_ref_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/copy_backward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/copy_move_common.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/copy_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/count.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/count_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/equal.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/equal_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/fill.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/fill_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/find.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/find_end.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/find_first_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/find_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/find_if_not.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/find_segment_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/for_each.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/for_each_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/for_each_n_segment.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/for_each_segment.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/generate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/generate_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/half_positive.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/in_found_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/in_fun_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/in_in_out_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/in_in_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/in_out_out_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/in_out_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/includes.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/inplace_merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/is_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/is_heap_until.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/is_partitioned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/is_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/is_sorted.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/is_sorted_until.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/iter_swap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/iterator_operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/lexicographical_compare.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/lexicographical_compare_three_way.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/lower_bound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/make_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/make_projected.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/max.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/max_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/min.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/min_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/min_max_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/minmax.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/minmax_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/mismatch.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/move.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/move_backward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/next_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/none_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/nth_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/out_value_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/partial_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/partial_sort_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/partition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/partition_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/partition_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/pop_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/prev_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/pstl.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/push_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/radix_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_adjacent_find.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_all_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_any_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_binary_search.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_clamp.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_contains.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_contains_subrange.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_copy_backward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_copy_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_count.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_count_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_ends_with.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_equal.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_equal_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_fill.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_fill_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_find.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_find_end.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_find_first_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_find_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_find_if_not.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_find_last.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_fold.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_for_each.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_for_each_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_generate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_generate_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_includes.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_inplace_merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_is_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_is_heap_until.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_is_partitioned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_is_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_is_sorted.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_is_sorted_until.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_iterator_concept.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_lexicographical_compare.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_lower_bound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_make_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_max.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_max_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_min.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_min_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_minmax.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_minmax_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_mismatch.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_move.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_move_backward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_next_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_none_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_nth_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_partial_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_partial_sort_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_partition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_partition_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_partition_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_pop_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_prev_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_push_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_remove.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_remove_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_remove_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_remove_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_replace.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_replace_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_replace_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_replace_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_reverse.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_reverse_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_rotate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_rotate_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_sample.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_search.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_search_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_set_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_set_intersection.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_set_symmetric_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_set_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_shuffle.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_sort_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_stable_partition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_stable_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_starts_with.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_swap_ranges.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_transform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_unique.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_unique_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/ranges_upper_bound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/remove.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/remove_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/remove_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/remove_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/replace.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/replace_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/replace_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/replace_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/reverse.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/reverse_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/rotate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/rotate_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/sample.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/search.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/search_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/set_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/set_intersection.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/set_symmetric_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/set_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/shift_left.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/shift_right.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/shuffle.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/sift_down.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/simd_utils.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/sort_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/specialized_algorithms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/stable_partition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/stable_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/swap_ranges.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/three_way_comp_ref_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/transform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/uniform_random_bit_generator_adaptor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/unique.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/unique_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/unwrap_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/unwrap_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__algorithm/upper_bound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__assert" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__assertion_handler" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/aliases.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_flag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_init.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_lock_free.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_sync.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_sync_timed.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/atomic_waitable_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/check_memory_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/contention_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/fence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/floating_point_helper.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/is_always_lock_free.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/kill_dependency.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/memory_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/support.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/support/c11.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/support/gcc.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__atomic/to_gcc_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/bit_cast.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/bit_ceil.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/bit_floor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/bit_log2.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/bit_width.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/blsr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/byteswap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/countl.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/countr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/endian.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/has_single_bit.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/invert_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/popcount.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit/rotate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__bit_reference" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/chars_format.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/from_chars_floating_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/from_chars_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/from_chars_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/tables.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/to_chars.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/to_chars_base_10.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/to_chars_floating_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/to_chars_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/to_chars_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__charconv/traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/calendar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/concepts.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/convert_to_timespec.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/convert_to_tm.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/day.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/duration.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/exception.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/file_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/formatter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/gps_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/hh_mm_ss.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/high_resolution_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/is_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/leap_second.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/literals.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/local_info.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/month.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/month_weekday.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/monthday.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/ostream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/parser_std_format_spec.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/statically_widen.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/steady_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/sys_info.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/system_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/tai_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/time_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/time_zone.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/time_zone_link.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/tzdb.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/tzdb_list.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/utc_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/weekday.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/year.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/year_month.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/year_month_day.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/year_month_weekday.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__chrono/zoned_time.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/common_comparison_category.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/compare_partial_order_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/compare_strong_order_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/compare_three_way.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/compare_three_way_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/compare_weak_order_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/is_eq.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/ordering.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/partial_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/strong_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/synth_three_way.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/three_way_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__compare/weak_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/arithmetic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/boolean_testable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/class_or_enum.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/common_reference_with.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/common_with.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/comparison_common_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/convertible_to.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/copyable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/derived_from.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/different_from.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/equality_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/invocable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/movable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/predicate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/regular.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/relation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/same_as.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/semiregular.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/swappable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__concepts/totally_ordered.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__condition_variable/condition_variable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__config" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__config_site" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/abi.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/availability.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/compiler.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/experimental.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/hardening.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/language.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__configuration/platform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__coroutine/coroutine_handle.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__coroutine/coroutine_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__coroutine/noop_coroutine_handle.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__coroutine/trivial_awaitables.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cstddef/byte.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cstddef/max_align_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cstddef/nullptr_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cstddef/ptrdiff_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cstddef/size_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/adjacent_find.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/all_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/any_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/binary_search.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/comp.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/comp_ref_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/copy_backward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/copy_move_common.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/copy_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/count.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/count_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/equal.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/equal_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/fill.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/fill_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/find.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/find_end.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/find_first_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/find_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/find_if_not.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/find_segment_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/for_each.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/for_each_segment.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/generate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/generate_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/half_positive.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/includes.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/inplace_merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/is_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/is_heap_until.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/is_partitioned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/is_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/is_sorted.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/is_sorted_until.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/iter_swap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/iterator_operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/lexicographical_compare.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/lower_bound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/make_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/make_projected.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/max.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/max_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/min.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/min_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/minmax.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/minmax_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/mismatch.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/move.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/move_backward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/next_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/none_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/nth_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/partial_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/partial_sort_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/partition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/partition_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/partition_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/pop_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/prev_permutation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/push_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/remove.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/remove_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/remove_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/remove_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/replace.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/replace_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/replace_copy_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/replace_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/reverse.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/reverse_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/rotate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/rotate_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/search.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/search_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/set_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/set_intersection.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/set_symmetric_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/set_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/shuffle.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/sift_down.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/simd_utils.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/sort_heap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/stable_partition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/stable_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/swap_ranges.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/three_way_comp_ref_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/transform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/uniform_random_bit_generator_adaptor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/unique.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/unique_copy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/unwrap_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/unwrap_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__algorithm/upper_bound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__assert" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/aliases.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/atomic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/atomic_base.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/atomic_flag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/atomic_init.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/atomic_lock_free.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/atomic_sync.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/check_memory_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/contention_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/cxx_atomic_impl.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/fence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/is_always_lock_free.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/kill_dependency.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/memory_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__atomic/to_gcc_order.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit/blsr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit/countl.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit/countr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit/invert_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit/popcount.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit/rotate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__bit_reference" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__chrono/convert_to_timespec.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__chrono/duration.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__chrono/high_resolution_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__chrono/steady_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__chrono/system_clock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__chrono/time_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__condition_variable/condition_variable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__config" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__configuration/abi.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__configuration/availability.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__configuration/compiler.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__configuration/config_site_shim.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__configuration/language.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__configuration/platform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__debug_utils/randomize_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__debug_utils/sanitizers.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__debug_utils/strict_weak_ordering_check.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__exception/exception.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__exception/exception_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__exception/nested_exception.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__exception/operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__exception/terminate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/binary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/binary_negate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/bind.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/binder1st.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/binder2nd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/hash.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/identity.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/mem_fn.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/mem_fun_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/pointer_to_binary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/pointer_to_unary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/reference_wrapper.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/unary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/unary_negate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__functional/weak_result_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/array.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/bit_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/complex.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/deque.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/fstream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/functional.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/ios.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/istream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/memory.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/ostream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/pair.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/queue.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/sstream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/stack.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/streambuf.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/string.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/string_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/tuple.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__fwd/vector.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__hash_table" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__ios/fpos.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/access.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/advance.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/aliasing_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/back_insert_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/bounded_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/distance.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/erase_if_container.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/front_insert_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/insert_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/istream_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/istreambuf_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/iterator_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/move_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/next.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/ostream_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/ostreambuf_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/prev.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/reverse_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/segmented_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__iterator/wrap_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/android.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/bsd_locale_defaults.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/bsd_locale_fallbacks.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/fuchsia.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/ibm.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/locale_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/musl.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/newlib.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/openbsd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__locale_dir/locale_base_api/win32.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/abs.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/copysign.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/error_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/exponential_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/fdim.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/fma.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/gamma.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/hyperbolic_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/hypot.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/inverse_hyperbolic_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/inverse_trigonometric_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/logarithms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/min_max.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/modulo.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/remainder.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/roots.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/rounding_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__math/trigonometric_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__mbstate_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/addressof.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/align.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/aligned_alloc.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/allocate_at_least.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/allocation_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/allocator_arg_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/allocator_destructor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/allocator_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/assume_aligned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/auto_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/builtin_new_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/compressed_pair.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/construct_at.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/destruct_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/pointer_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/raw_storage_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/shared_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/swap_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/temp_value.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/temporary_buffer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/uninitialized_algorithms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/unique_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/uses_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__memory/voidify.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__mutex/lock_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__mutex/mutex.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__mutex/once_flag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__mutex/tag_types.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__mutex/unique_lock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__numeric/accumulate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__numeric/adjacent_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__numeric/inner_product.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__numeric/iota.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__numeric/partial_sum.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__ostream/basic_ostream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/bernoulli_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/binomial_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/cauchy_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/chi_squared_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/clamp_to_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/default_random_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/discard_block_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/discrete_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/exponential_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/extreme_value_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/fisher_f_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/gamma_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/generate_canonical.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/geometric_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/independent_bits_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/is_seed_sequence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/is_valid.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/knuth_b.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/linear_congruential_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/log2.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/lognormal_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/mersenne_twister_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/negative_binomial_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/normal_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/piecewise_constant_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/piecewise_linear_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/poisson_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/random_device.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/ranlux.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/seed_seq.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/shuffle_order_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/student_t_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/subtract_with_carry_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/uniform_int_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/uniform_real_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__random/weibull_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__split_buffer" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__std_clang_module" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__std_mbstate_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__string/char_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__string/constexpr_c_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__string/extern_template_lists.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__support/ibm/gettod_zos.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__support/ibm/locale_mgmt_zos.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__support/ibm/nanosleep.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__support/xlocale/__nop_locale_mgmt.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__support/xlocale/__posix_l_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__support/xlocale/__strtonum_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__system_error/errc.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__system_error/error_category.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__system_error/error_code.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__system_error/error_condition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__system_error/system_error.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/id.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/poll_with_backoff.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/support.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/support/c11.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/support/external.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/support/pthread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/support/windows.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/this_thread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/thread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__thread/timed_backoff_policy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tree" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/find_index.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/make_tuple_types.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/sfinae_helpers.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_indices.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_like.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_like_ext.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_like_no_subrange.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_size.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__tuple/tuple_types.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/add_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/add_cv.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/add_lvalue_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/add_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/add_rvalue_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/add_volatile.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/aligned_storage.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/aligned_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/alignment_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/can_extract_key.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/common_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/conditional.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/conjunction.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/copy_cv.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/copy_cvref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/datasizeof.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/decay.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/dependent_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/desugars_to.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/disjunction.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/enable_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/extent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/has_virtual_destructor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/integral_constant.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/invoke.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_abstract.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_always_bitcastable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_arithmetic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_array.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_base_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_bounded_array.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_callable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_char_like_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_class.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_compound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_constant_evaluated.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_convertible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_core_convertible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_empty.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_enum.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_equality_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_execution_policy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_final.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_floating_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_fundamental.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_implicitly_default_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_literal_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_member_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_nothrow_assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_nothrow_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_nothrow_destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_null_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_object.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_pod.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_polymorphic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_primary_template.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_reference_wrapper.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_referenceable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_same.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_scalar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_signed.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_signed_integer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_specialization.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_standard_layout.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_swappable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivial.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_copyable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_lexicographically_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_trivially_relocatable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_unbounded_array.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_unsigned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_unsigned_integer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_valid_expansion.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_void.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/is_volatile.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/lazy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/make_32_64_or_128_bit.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/make_const_lvalue_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/make_signed.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/make_unsigned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/maybe_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/nat.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/negation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/noexcept_move_assign_container.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/promote.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/rank.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_all_extents.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_const_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_cv.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_cvref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_extent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/remove_volatile.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/result_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/strip_signature.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/type_identity.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/type_list.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/underlying_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/unwrap_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__type_traits/void_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__undef_macros" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/as_lvalue.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/auto_cast.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/convert_to_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/declval.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/empty.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/exception_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/forward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/integer_sequence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/is_pointer_in_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/is_valid_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/move.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/no_destroy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/pair.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/piecewise_construct.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/priority_tag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/private_constructor_tag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/rel_ops.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/small_buffer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/swap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__utility/unreachable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__variant/monostate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__verbose_abort" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/__verbose_trap" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/algorithm" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/array" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/atomic" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/bitset" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cassert" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ccomplex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cctype" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cerrno" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cfenv" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cfloat" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/chrono" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cinttypes" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ciso646" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/climits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/clocale" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cmath" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/codecvt" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/complex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/condition_variable" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/csetjmp" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/csignal" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstdarg" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstdbool" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstddef" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstdint" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstdio" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstdlib" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cstring" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ctgmath" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ctime" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cuchar" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cwchar" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/cwctype" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/deque" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/exception" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/experimental/__config" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/experimental/utility" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ext/__hash" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ext/hash_map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ext/hash_set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/forward_list" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/fstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/functional" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/future" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/iomanip" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ios" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/iosfwd" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/iostream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/istream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/iterator" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/limits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/list" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/locale" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/locale.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/math.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/memory" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/module.modulemap" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/mutex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/new" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/numeric" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ostream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/queue" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/random" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/ratio" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/regex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/sstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/stack" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/stdatomic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/stdexcept" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/stdint.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/stdlib.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/streambuf" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/string" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/string.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/string_view" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/strstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/system_error" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/thread" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/type_traits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/typeindex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/typeinfo" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/uchar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/unordered_map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/unordered_set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/utility" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/valarray" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/vector" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/version" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxx03/wchar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__cxxabi_config.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__debug_utils/randomize_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__debug_utils/sanitizers.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__debug_utils/strict_weak_ordering_check.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__exception/exception.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__exception/exception_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__exception/nested_exception.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__exception/operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__exception/terminate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__expected/bad_expected_access.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__expected/expected.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__expected/unexpect.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__expected/unexpected.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/copy_options.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/directory_entry.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/directory_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/directory_options.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/file_status.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/file_time_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/file_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/filesystem_error.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/path.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/path_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/perm_options.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/perms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/recursive_directory_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/space_info.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__filesystem/u8path.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_map/flat_map.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_map/flat_multimap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_map/key_value_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_map/sorted_equivalent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_map/sorted_unique.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_map/utils.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_set/flat_multiset.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_set/flat_set.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_set/ra_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__flat_set/utils.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/buffer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/concepts.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/container_adaptor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/enable_insertable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/escaped_output_table.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/extended_grapheme_cluster_table.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/fmt_pair_like.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_arg.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_arg_store.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_args.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_context.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_error.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_parse_context.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_string.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/format_to_n_result.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_bool.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_char.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_floating_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_integer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_output.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_string.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/formatter_tuple.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/indic_conjunct_break_table.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/parser_std_format_spec.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/range_default_formatter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/range_format.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/range_formatter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/unicode.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/width_estimation_table.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__format/write_escaped.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/binary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/binary_negate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/bind.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/bind_back.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/bind_front.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/binder1st.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/binder2nd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/boyer_moore_searcher.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/compose.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/default_searcher.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/hash.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/identity.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/invoke.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/is_transparent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/mem_fn.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/mem_fun_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/not_fn.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/perfect_forward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/pointer_to_binary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/pointer_to_unary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/ranges_operations.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/reference_wrapper.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/unary_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/unary_negate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__functional/weak_result_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/array.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/bit_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/byte.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/complex.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/deque.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/format.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/fstream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/functional.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/get.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/ios.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/istream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/mdspan.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/memory.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/memory_resource.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/ostream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/pair.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/queue.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/span.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/sstream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/stack.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/streambuf.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/string.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/string_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/subrange.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/tuple.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/variant.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__fwd/vector.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__hash_table" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ios/fpos.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/access.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/advance.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/aliasing_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/back_insert_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/bounded_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/common_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/concepts.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/counted_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/cpp17_iterator_concepts.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/data.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/default_sentinel.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/distance.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/empty.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/erase_if_container.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/front_insert_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/incrementable_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/indirectly_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/insert_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/istream_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/istreambuf_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/iter_move.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/iter_swap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/iterator_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/iterator_with_data.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/mergeable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/move_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/move_sentinel.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/next.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/ostream_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/ostreambuf_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/permutable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/prev.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/product_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/projected.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/ranges_iterator_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/readable_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/reverse_access.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/reverse_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/segmented_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/size.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/sortable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/static_bounded_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/unreachable_sentinel.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__iterator/wrap_iter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/check_grouping.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/get_c_locale.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/locale_base_api.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/locale_base_api/bsd_locale_fallbacks.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/locale_base_api/ibm.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/locale_base_api/openbsd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/messages.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/money.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/num.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/pad_and_output.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/scan_keyword.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/aix.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/apple.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/bsd_like.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/freebsd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/fuchsia.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/linux.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/netbsd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/newlib.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/no_locale/characters.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/no_locale/strtonum.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/support/windows.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/time.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/wbuffer_convert.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__locale_dir/wstring_convert.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__log_hardening_failure" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/abs.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/copysign.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/error_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/exponential_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/fdim.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/fma.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/gamma.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/hyperbolic_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/hypot.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/inverse_hyperbolic_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/inverse_trigonometric_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/logarithms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/min_max.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/modulo.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/remainder.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/roots.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/rounding_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/special_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__math/trigonometric_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mbstate_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/aligned_accessor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/default_accessor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/extents.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/layout_left.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/layout_right.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/layout_stride.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mdspan/mdspan.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/addressof.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/align.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/allocate_at_least.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/allocation_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/allocator_arg_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/allocator_destructor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/allocator_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/array_cookie.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/assume_aligned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/auto_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/compressed_pair.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/concepts.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/construct_at.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/destroy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/destruct_n.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/inout_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/is_sufficiently_aligned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/noexcept_move_assign_container.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/out_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/pointer_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/ranges_construct_at.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/ranges_destroy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/ranges_uninitialized_algorithms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/raw_storage_iterator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/shared_count.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/shared_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/swap_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/temp_value.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/temporary_buffer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/uninitialized_algorithms.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/unique_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/unique_temporary_buffer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/uses_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory/uses_allocator_construction.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory_resource/memory_resource.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory_resource/monotonic_buffer_resource.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory_resource/polymorphic_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory_resource/pool_options.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory_resource/synchronized_pool_resource.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__memory_resource/unsynchronized_pool_resource.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mutex/lock_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mutex/mutex.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mutex/once_flag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mutex/tag_types.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__mutex/unique_lock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/align_val_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/allocate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/destroying_delete_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/exceptions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/global_new_delete.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/interference_size.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/launder.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/new_handler.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/nothrow_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__new/placement_new_delete.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__node_handle" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/accumulate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/adjacent_difference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/exclusive_scan.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/gcd_lcm.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/inclusive_scan.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/inner_product.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/iota.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/midpoint.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/partial_sum.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/pstl.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/ranges_iota.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/reduce.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/saturation_arithmetic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/transform_exclusive_scan.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/transform_inclusive_scan.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__numeric/transform_reduce.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ostream/basic_ostream.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ostream/print.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ostream/put_character_sequence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/backend.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/backend_fwd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/backends/default.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/backends/libdispatch.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/backends/serial.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/backends/std_thread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/any_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/cpu_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/fill.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/find_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/for_each.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/merge.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/stable_sort.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/transform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/cpu_algos/transform_reduce.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/dispatch.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__pstl/handle_exception.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/bernoulli_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/binomial_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/cauchy_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/chi_squared_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/clamp_to_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/default_random_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/discard_block_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/discrete_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/exponential_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/extreme_value_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/fisher_f_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/gamma_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/generate_canonical.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/geometric_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/independent_bits_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/is_seed_sequence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/is_valid.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/knuth_b.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/linear_congruential_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/log2.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/lognormal_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/mersenne_twister_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/negative_binomial_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/normal_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/piecewise_constant_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/piecewise_linear_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/poisson_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/random_device.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/ranlux.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/seed_seq.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/shuffle_order_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/student_t_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/subtract_with_carry_engine.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/uniform_int_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/uniform_random_bit_generator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/uniform_real_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__random/weibull_distribution.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/access.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/adjacent_transform_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/adjacent_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/all.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/as_rvalue_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/chunk_by_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/common_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/concepts.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/container_compatible_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/counted.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/dangling.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/data.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/drop_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/drop_while_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/elements_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/elements_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/empty.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/empty_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/enable_borrowed_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/enable_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/filter_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/from_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/iota_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/istream_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/join_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/join_with_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/lazy_split_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/movable_box.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/non_propagating_cache.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/owning_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/range_adaptor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/rbegin.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/ref_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/rend.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/repeat_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/reverse_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/single_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/size.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/split_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/subrange.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/take_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/take_while_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/to.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/transform_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/view_interface.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/views.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/zip_transform_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__ranges/zip_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__split_buffer" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__std_mbstate_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/atomic_unique_lock.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/intrusive_list_view.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/intrusive_shared_ptr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/stop_callback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/stop_source.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/stop_state.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__stop_token/stop_token.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__string/char_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__string/constexpr_c_functions.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__string/extern_template_lists.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__support/ibm/gettod_zos.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__support/ibm/locale_mgmt_zos.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__support/ibm/nanosleep.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__support/xlocale/__nop_locale_mgmt.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__support/xlocale/__posix_l_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__support/xlocale/__strtonum_fallback.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__system_error/errc.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__system_error/error_category.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__system_error/error_code.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__system_error/error_condition.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__system_error/system_error.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__system_error/throw_system_error.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/formatter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/id.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/jthread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/poll_with_backoff.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/support.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/support/c11.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/support/external.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/support/pthread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/support/windows.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/this_thread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/thread.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__thread/timed_backoff_policy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tree" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/find_index.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/ignore.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/sfinae_helpers.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/tuple_element.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/tuple_like.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/tuple_like_no_subrange.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/tuple_size.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__tuple/tuple_transform.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/add_cv_quals.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/add_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/add_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/aligned_storage.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/aligned_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/alignment_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/common_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/common_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/conditional.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/conjunction.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/container_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/copy_cv.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/copy_cvref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/datasizeof.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/decay.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/dependent_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/desugars_to.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/detected_or.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/disjunction.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/enable_if.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/extent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/has_unique_object_representation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/has_virtual_destructor.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/integer_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/integral_constant.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/invoke.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_abstract.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_aggregate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_allocator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_always_bitcastable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_arithmetic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_array.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_base_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_callable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_char_like_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_class.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_compound.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_constant_evaluated.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_convertible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_core_convertible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_empty.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_enum.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_equality_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_execution_policy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_final.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_floating_point.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_function.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_fundamental.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_generic_transparent_comparator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_implicit_lifetime.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_implicitly_default_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_literal_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_member_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_nothrow_assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_nothrow_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_nothrow_destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_null_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_object.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_pod.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_polymorphic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_primary_template.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_reference_wrapper.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_referenceable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_same.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_scalar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_signed.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_specialization.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_standard_layout.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_swappable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivial.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivially_assignable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivially_constructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivially_copyable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivially_destructible.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivially_lexicographically_comparable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_trivially_relocatable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_union.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_unqualified.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_unsigned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_valid_expansion.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_void.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_volatile.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/is_within_lifetime.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/lazy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/make_32_64_or_128_bit.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/make_const_lvalue_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/make_signed.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/make_transparent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/make_unsigned.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/maybe_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/nat.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/negation.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/promote.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/rank.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/reference_constructs_from_temporary.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/reference_converts_from_temporary.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_all_extents.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_const_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_cv.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_cvref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_extent.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_pointer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/remove_volatile.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/result_of.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/strip_signature.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/type_identity.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/type_list.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/underlying_type.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/unwrap_ref.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__type_traits/void_t.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__undef_macros" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/as_const.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/as_lvalue.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/auto_cast.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/cmp.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/convert_to_integral.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/declval.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/default_three_way_comparator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/element_count.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/empty.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/exception_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/exchange.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/forward.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/forward_like.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/in_place.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/integer_sequence.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/is_pointer_in_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/is_valid_range.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/lazy_synth_three_way_comparator.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/move.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/no_destroy.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/pair.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/piecewise_construct.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/priority_tag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/private_constructor_tag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/rel_ops.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/scope_guard.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/small_buffer.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/swap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/to_underlying.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/try_key_extraction.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__utility/unreachable.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__variant/monostate.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/comparison.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/container_traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/erase.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/pmr.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/swap.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/vector.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/vector_bool.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__vector/vector_bool_formatter.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__verbose_abort" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/__verbose_trap" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/algorithm" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/any" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/array" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/atomic" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/barrier" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/bit" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/bitset" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cassert" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ccomplex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cctype" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cerrno" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cfenv" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cfloat" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/charconv" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/chrono" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cinttypes" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ciso646" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/climits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/clocale" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cmath" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/codecvt" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/compare" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/complex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/complex.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/concepts" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/condition_variable" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/coroutine" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/csetjmp" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/csignal" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstdalign" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstdarg" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstdbool" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstddef" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstdint" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstdio" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstdlib" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cstring" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ctgmath" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ctime" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ctype.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cuchar" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cwchar" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cwctype" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/cxxabi.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/deque" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/errno.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/exception" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/execution" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/expected" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/aligned_tag.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/declaration.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/reference.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/scalar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/simd.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/simd_mask.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/traits.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/utility.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/__simd/vec_ext.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/iterator" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/memory" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/propagate_const" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/simd" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/type_traits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/experimental/utility" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ext/__hash" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ext/hash_map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ext/hash_set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/fenv.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/filesystem" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/flat_map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/flat_set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/float.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/format" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/forward_list" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/fstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/functional" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/future" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/initializer_list" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/inttypes.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/iomanip" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ios" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/iosfwd" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/iostream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/istream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/iterator" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/latch" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/libcxx.imp" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/limits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/list" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/locale" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/math.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/mdspan" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/memory" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/memory_resource" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/module.modulemap" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/mutex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/new" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/numbers" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/numeric" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/optional" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ostream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/print" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/queue" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/random" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ranges" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/ratio" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/regex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/scoped_allocator" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/semaphore" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/shared_mutex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/source_location" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/span" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/sstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stack" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stdatomic.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stddef.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stdexcept" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stdio.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stdlib.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/stop_token" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/streambuf" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/string" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/string.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/string_view" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/strstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/syncstream" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/system_error" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/tgmath.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/thread" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/tuple" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/type_traits" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/typeindex" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/typeinfo" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/uchar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/unordered_map" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/unordered_set" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/utility" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/valarray" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/variant" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/vector" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/version" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/wchar.h" + textual header "/nix/store/pqgwpyp04mcvfd468imrcxwyagbklw03-libcxx-22.1.8-dev/include/c++/v1/wctype.h" } diff --git a/local-remote-execution/generated-cc/cc/validate_static_library.sh b/local-remote-execution/generated-cc/cc/validate_static_library.sh index 15795bc31..ffaae6042 100644 --- a/local-remote-execution/generated-cc/cc/validate_static_library.sh +++ b/local-remote-execution/generated-cc/cc/validate_static_library.sh @@ -1,4 +1,4 @@ -#!/nix/store/i7hwka78f6i34v4r211ynr6nnafcba7f-bash/bin/bash +#!/nix/store/x4xf1dbpn5q4lkx1a5c9mxy5300gacc1-bash/bin/bash # # Copyright 2023 The Bazel Authors. All rights reserved. # @@ -30,11 +30,11 @@ set -euo pipefail # of nm because it is not in POSIX and demangled names may not be unique # (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35201). DUPLICATE_SYMBOLS=$( - "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/nm" -A -g -P "$1" | + "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/nm" -A -g -P "$1" | sed -E -e 's/.*\[([^][]+)\]: (.+) ([A-TX-Z]) [a-f0-9]+ [a-f0-9]+/\1: \3 \2/g' -e t -e d | LC_ALL=C sort -k 3 | LC_ALL=C uniq -D -f 2 | - "/nix/store/lrp069m8jb7gm0xaj8ww4gp37zwczc0z-llvm-binutils-wrapper-22.1.0-rc3/bin/c++filt" + "/nix/store/c5z0kxmshkd2j8bflq22ya45f7fssn0l-llvm-binutils-wrapper-22.1.8/bin/c++filt" ) if [[ -n $DUPLICATE_SYMBOLS ]]; then >&2 echo "Duplicate symbols found in $1:" diff --git a/local-remote-execution/generated-cc/config/BUILD b/local-remote-execution/generated-cc/config/BUILD index 6a3a7d4ba..177218c70 100644 --- a/local-remote-execution/generated-cc/config/BUILD +++ b/local-remote-execution/generated-cc/config/BUILD @@ -40,7 +40,7 @@ platform( "@bazel_tools//tools/cpp:clang", ], exec_properties = { - "container-image": "docker://lre-cc:zms5771rx1yqb4wd6qbj5f9sb2paq75k", + "container-image": "docker://lre-cc:nz62ssm01zq2sq4768h58lnfalmpr7bz", "OSFamily": "Linux", }, parents = ["@platforms//host"], diff --git a/local-remote-execution/rust/extension.bzl b/local-remote-execution/rust/extension.bzl index 646f0a0af..b4c66ca03 100644 --- a/local-remote-execution/rust/extension.bzl +++ b/local-remote-execution/rust/extension.bzl @@ -30,42 +30,42 @@ def _lre_rs_impl(_mctx): new_local_repository( name = "lre-rs-stable-aarch64-darwin", build_file = "@local-remote-execution//rust:aarch64-darwin.BUILD.bazel", - path = "/nix/store/hnaxvxm1n6z37n2zfb9vgknq99xr2jha-rust-default-1.93.1", + path = "/nix/store/2mchcvza9v1j5mx67r4770plmrkm0f68-rust-default-1.93.1", ) new_local_repository( name = "lre-rs-nightly-aarch64-darwin", build_file = "@local-remote-execution//rust:aarch64-darwin.BUILD.bazel", - path = "/nix/store/f3fkv17h8wlnkm026m09vgxyfjhhxp9c-rust-default-1.96.0-nightly-2026-03-24", + path = "/nix/store/1dysg6qbzyb7vanwsc5y756zmb0227z9-rust-default-1.96.0-nightly-2026-03-24", ) new_local_repository( name = "lre-rs-stable-aarch64-linux", build_file = "@local-remote-execution//rust:aarch64-linux.BUILD.bazel", - path = "/nix/store/5vqbs2b3296x8c82xm5scz29n8y2zm0h-rust-default-1.93.1", + path = "/nix/store/vx2ziqrqc0qj0pjng71cpcyainq52xqd-rust-default-1.93.1", ) new_local_repository( name = "lre-rs-nightly-aarch64-linux", build_file = "@local-remote-execution//rust:aarch64-linux.BUILD.bazel", - path = "/nix/store/vji1aridxgaiqrcpagnb6iqf3003b50r-rust-default-1.96.0-nightly-2026-03-24", + path = "/nix/store/zl02i3a6zzw5mxd665y2n7mp97ajdwkx-rust-default-1.96.0-nightly-2026-03-24", ) new_local_repository( name = "lre-rs-stable-x86_64-darwin", build_file = "@local-remote-execution//rust:x86_64-darwin.BUILD.bazel", - path = "/nix/store/kj59hbxsrfsgw3qz5lv3drkhfx2md2sf-rust-default-1.93.1", + path = "/nix/store/qjpia0l98w7wpf9b3nzfb24y8rxh52cg-rust-default-1.93.1", ) new_local_repository( name = "lre-rs-nightly-x86_64-darwin", build_file = "@local-remote-execution//rust:x86_64-darwin.BUILD.bazel", - path = "/nix/store/hqnbzi9zh1jaf957czfs5li266as95bw-rust-default-1.96.0-nightly-2026-03-24", + path = "/nix/store/wdyvk55ys5m7shpp6jw9d8116m3dlmjd-rust-default-1.96.0-nightly-2026-03-24", ) new_local_repository( name = "lre-rs-stable-x86_64-linux", build_file = "@local-remote-execution//rust:x86_64-linux.BUILD.bazel", - path = "/nix/store/1sg0jgxw6k6jy8a3wvfacmnrdii236i0-rust-default-1.93.1", + path = "/nix/store/cgzz6kbvvhxh4k71rlj9wj14mdbn02n9-rust-default-1.93.1", ) new_local_repository( name = "lre-rs-nightly-x86_64-linux", build_file = "@local-remote-execution//rust:x86_64-linux.BUILD.bazel", - path = "/nix/store/j7v0r10lpysj1ak70g32rz8rdwbwn5sl-rust-default-1.96.0-nightly-2026-03-24", + path = "/nix/store/5pysp36qjzbwdjx9zlj9sjc43zhbiwyn-rust-default-1.96.0-nightly-2026-03-24", ) lre_rs = module_extension(implementation = _lre_rs_impl) diff --git a/local-remote-execution/rust/platforms/BUILD.bazel b/local-remote-execution/rust/platforms/BUILD.bazel index a034fb991..a28acbe2b 100644 --- a/local-remote-execution/rust/platforms/BUILD.bazel +++ b/local-remote-execution/rust/platforms/BUILD.bazel @@ -23,7 +23,7 @@ platform( name = "aarch64-apple-darwin", exec_properties = { # tag is from nix eval .#packages.aarch64-darwin.nativelink-worker-lre-rs.imageTag - "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:yhrc25xbirgjrh8zxqp44ysq5wibr5yb", + "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:cqzqrwpx7hfvir24hj06m4y5s5nxym5g", }, parents = ["@local-remote-execution//platforms:aarch64-darwin"], ) @@ -33,7 +33,7 @@ platform( constraint_values = ["@local-remote-execution//libc:glibc"], exec_properties = { # tag is from nix eval .#packages.aarch64-linux.nativelink-worker-lre-rs.imageTag - "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:8h9253qs3c1dcz80xjdj352b66ksm58c", + "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:xy9qmvic63aczmix71dgzg5dfrlq1if8", }, parents = ["@local-remote-execution//platforms:aarch64-linux"], ) @@ -43,7 +43,7 @@ platform( constraint_values = ["@local-remote-execution//libc:musl"], exec_properties = { # tag is from nix eval .#packages.aarch64-linux.nativelink-worker-lre-rs.imageTag - "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:8h9253qs3c1dcz80xjdj352b66ksm58c", + "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:xy9qmvic63aczmix71dgzg5dfrlq1if8", }, parents = ["@local-remote-execution//platforms:aarch64-linux"], ) @@ -52,7 +52,7 @@ platform( name = "x86_64-apple-darwin", exec_properties = { # tag is from nix eval .#packages.x86_64-darwin.nativelink-worker-lre-rs.imageTag - "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:09pcycn3y2lblpd64cdca8sm6vvwzalv", + "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:hz9s5p98hy5hgkn6ab0ny13fsi25b491", }, parents = ["@local-remote-execution//platforms:x86_64-darwin"], ) @@ -62,7 +62,7 @@ platform( constraint_values = ["@local-remote-execution//libc:glibc"], exec_properties = { # tag is from nix eval .#packages.x86_64-linux.nativelink-worker-lre-rs.imageTag - "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:l9azdnlsva9az170z9l61ph78xpcxjbw", + "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:1hvvyzz0z4rs6d9arlnxc05pxz8qz7zj", }, parents = ["@local-remote-execution//platforms:x86_64-linux"], ) @@ -72,7 +72,7 @@ platform( constraint_values = ["@local-remote-execution//libc:musl"], exec_properties = { # tag is from nix eval .#packages.x86_64-linux.nativelink-worker-lre-rs.imageTag - "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:l9azdnlsva9az170z9l61ph78xpcxjbw", + "container-image": "ghcr.io/tracemachina/nativelink-worker-lre-rs:1hvvyzz0z4rs6d9arlnxc05pxz8qz7zj", }, parents = ["@local-remote-execution//platforms:x86_64-linux"], ) diff --git a/nativelink-config/Cargo.toml b/nativelink-config/Cargo.toml index 0b2474206..6f10dd847 100644 --- a/nativelink-config/Cargo.toml +++ b/nativelink-config/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-config" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-error = { path = "../nativelink-error" } diff --git a/nativelink-config/README.md b/nativelink-config/README.md index 6c8856a16..9d5a39861 100644 --- a/nativelink-config/README.md +++ b/nativelink-config/README.md @@ -281,6 +281,63 @@ If `access_key_id` and `secret_access_key` are omitted, NativeLink falls back to the standard AWS credential chain (`AWS_*` env vars, `~/.aws/credentials`, IMDS). +### OCI Store + +[Oracle Cloud Infrastructure Object Storage](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) +exposes an S3-compatible API, so NativeLink can use it as a CAS/AC backend. The +path-style endpoint is derived from your Object Storage `namespace` and +`region` as +`https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. +Authenticate with a Customer Secret Key (an Access Key/Secret Key pair created +under **User Settings → Customer secret keys** in the OCI console); the secret +cannot be retrieved after generation, so read it from an env var via +`shellexpand`. + +```js +{ + "stores": [ + { + "name": "CAS_MAIN_STORE", + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "${OCI_ACCESS_KEY_ID}", + "secret_access_key": "${OCI_SECRET_ACCESS_KEY}", + "key_prefix": "cas/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5, + } + } + }, + { + "name": "AC_MAIN_STORE", + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "${OCI_ACCESS_KEY_ID}", + "secret_access_key": "${OCI_SECRET_ACCESS_KEY}", + "key_prefix": "ac/", + } + } + ], + // Place rest of configuration here ... +} +``` + +A complete runnable example with CAS and AC is at +[`nativelink-config/examples/oci_backend.json5`](https://github.com/TraceMachina/nativelink/blob/main/nativelink-config/examples/oci_backend.json5). +The `region` is used both to build the endpoint host and as the AWS `SigV4` +signing region; if your tooling cannot set an OCI region identifier, OCI also +accepts `us-east-1` to target your tenancy home region. As with the other +S3-compatible stores, omitting `access_key_id` and `secret_access_key` falls +back to the standard AWS credential chain (`AWS_*` env vars). + ### Fast Slow Store This store will first attempt to read from the `fast` store when reading and if diff --git a/nativelink-config/examples/advanced_http.json5 b/nativelink-config/examples/advanced_http.json5 new file mode 100644 index 000000000..c5841d4bc --- /dev/null +++ b/nativelink-config/examples/advanced_http.json5 @@ -0,0 +1,231 @@ +{ + stores: [ + { + name: "AC_MAIN_STORE", + filesystem: { + content_path: "/tmp/nativelink/data-worker-test/content_path-ac", + temp_path: "/tmp/nativelink/data-worker-test/tmp_path-ac", + eviction_policy: { + // 1gb. + max_bytes: 1000000000, + }, + }, + }, + { + name: "WORKER_FAST_SLOW_STORE", + fast_slow: { + // "fast" must be a "filesystem" store because the worker uses it to make + // hardlinks on disk to a directory where the jobs are running. + fast: { + filesystem: { + content_path: "/tmp/nativelink/data-worker-test/content_path-cas", + temp_path: "/tmp/nativelink/data-worker-test/tmp_path-cas", + eviction_policy: { + // 10gb. + max_bytes: 10000000000, + }, + }, + }, + slow: { + /// Discard data. + /// This example usage has the CAS and the Worker live in the same place, + /// so they share the same underlying CAS. Since workers require a fast_slow + /// store, we use the fast store as our primary data store, and the slow store + /// is just a noop, since there's no shared storage in this config. + noop: {}, + }, + }, + }, + ], + schedulers: [ + { + name: "MAIN_SCHEDULER", + simple: { + supported_platform_properties: { + cpu_count: "minimum", + memory_kb: "minimum", + network_kbps: "minimum", + disk_read_iops: "minimum", + disk_read_bps: "minimum", + disk_write_iops: "minimum", + disk_write_bps: "minimum", + shm_size: "minimum", + gpu_count: "minimum", + gpu_model: "exact", + cpu_vendor: "exact", + cpu_arch: "exact", + cpu_model: "exact", + kernel_version: "exact", + OSFamily: "priority", + "container-image": "priority", + "lre-rs": "priority", + ISA: "exact", + InputRootAbsolutePath: "ignore", // used by chromium builds, but we can drop it + }, + }, + }, + ], + workers: [ + { + local: { + worker_api_endpoint: { + uri: "grpc://127.0.0.1:50061", + }, + cas_fast_slow_store: "WORKER_FAST_SLOW_STORE", + upload_action_result: { + ac_store: "AC_MAIN_STORE", + }, + work_directory: "/tmp/nativelink/work", + additional_environment: { + foo: "from_environment", + bar: { + value: "something", + }, + baz: "timeout_millis", + channel: "side_channel_file", + action: "action_directory", + }, + platform_properties: { + cpu_count: { + values: [ + "16", + ], + }, + memory_kb: { + values: [ + "500000", + ], + }, + network_kbps: { + values: [ + "100000", + ], + }, + cpu_arch: { + values: [ + "x86_64", + ], + }, + OSFamily: { + values: [ + "", + ], + }, + "container-image": { + values: [ + "", + ], + }, + "lre-rs": { + values: [ + "", + ], + }, + ISA: { + values: [ + "x86-64", + ], + }, + }, + }, + }, + ], + servers: [ + { + name: "public", + listener: { + http: { + socket_address: "0.0.0.0:50051", + advanced_http: { + http2_keep_alive_interval: 60, + experimental_http2_keep_alive_timeout: 20, + experimental_http2_max_concurrent_streams: 2000, + experimental_http2_max_pending_accept_reset_streams: 2000, + experimental_http2_initial_connection_window_size: 16777216, + experimental_http2_initial_stream_window_size: 8388608, + }, + }, + }, + services: { + cas: [ + { + instance_name: "", + cas_store: "WORKER_FAST_SLOW_STORE", + }, + { + instance_name: "main", + cas_store: "WORKER_FAST_SLOW_STORE", + }, + ], + ac: [ + { + instance_name: "", + ac_store: "AC_MAIN_STORE", + }, + { + instance_name: "main", + ac_store: "AC_MAIN_STORE", + }, + ], + execution: [ + { + instance_name: "", + cas_store: "WORKER_FAST_SLOW_STORE", + scheduler: "MAIN_SCHEDULER", + }, + { + instance_name: "main", + cas_store: "WORKER_FAST_SLOW_STORE", + scheduler: "MAIN_SCHEDULER", + }, + ], + capabilities: [ + { + instance_name: "", + remote_execution: { + scheduler: "MAIN_SCHEDULER", + }, + }, + { + instance_name: "main", + remote_execution: { + scheduler: "MAIN_SCHEDULER", + }, + }, + ], + bytestream: [ + { + instance_name: "", + cas_store: "WORKER_FAST_SLOW_STORE", + }, + { + instance_name: "main", + cas_store: "WORKER_FAST_SLOW_STORE", + }, + ], + }, + }, + { + name: "private_workers_servers", + listener: { + http: { + socket_address: "0.0.0.0:50061", + }, + }, + services: { + // Note: This should be served on a different port, because it has + // a different permission set than the other services. + // In other words, this service is a backend api. The ones above + // are a frontend api. + worker_api: { + scheduler: "MAIN_SCHEDULER", + }, + admin: {}, + health: {}, + }, + }, + ], + global: { + max_open_files: 24576, + }, +} diff --git a/nativelink-config/examples/chunking_cas.json5 b/nativelink-config/examples/chunking_cas.json5 new file mode 100644 index 000000000..f2ca4b966 --- /dev/null +++ b/nativelink-config/examples/chunking_cas.json5 @@ -0,0 +1,105 @@ +// Demonstrates REAPI content-defined chunking: the SplitBlob/SpliceBlob +// RPCs used by Bazel's --experimental_remote_cache_chunking flag +// (available in Bazel 8.7.0+ / 9.1.0+). +// +// Chunking is entirely optional and disabled by default: without the +// `experimental_chunking` block below, NativeLink behaves exactly as +// before and does not advertise chunking support. When enabled, clients +// upload and download large blobs as content-defined chunks, so small +// changes to large outputs only transfer the chunks that changed. +{ + stores: [ + { + name: "CAS_MAIN_STORE", + filesystem: { + content_path: "/tmp/nativelink/data/content_path-cas", + temp_path: "/tmp/nativelink/data/tmp_path-cas", + eviction_policy: { + // 10gb. + max_bytes: 10000000000, + }, + }, + }, + { + // Holds the blob-to-chunks layouts registered via SpliceBlob or + // created by on-demand chunking in SplitBlob. Layout entries are + // small (roughly 80-140 bytes per chunk). This store must not verify + // content digests and must not be the same store as the CAS itself. + name: "CHUNK_INDEX_STORE", + filesystem: { + content_path: "/tmp/nativelink/data/content_path-chunk-index", + temp_path: "/tmp/nativelink/data/tmp_path-chunk-index", + eviction_policy: { + // 100mb. + max_bytes: 100000000, + }, + }, + }, + { + name: "AC_MAIN_STORE", + filesystem: { + content_path: "/tmp/nativelink/data/content_path-ac", + temp_path: "/tmp/nativelink/data/tmp_path-ac", + eviction_policy: { + // 500mb. + max_bytes: 500000000, + }, + }, + }, + ], + servers: [ + { + listener: { + http: { + socket_address: "0.0.0.0:50051", + }, + }, + services: { + cas: [ + { + instance_name: "main", + cas_store: "CAS_MAIN_STORE", + + // Optional: omit this block to disable chunking entirely. + experimental_chunking: { + // Required, unless `cas_store` is a grpc store — in that + // case the chunking RPCs are forwarded to the backend and + // `index_store` must be omitted. + index_store: "CHUNK_INDEX_STORE", + + // Optional: the average chunk size in bytes advertised to + // clients and used for server-side chunking. Must be between + // 1 KiB and 1 MiB. + // Default: 524288 (512 KiB). + avg_chunk_size_bytes: 524288, + + // Optional: blobs that would produce more chunks than this + // are served without chunking. + // Default: 50000. + max_chunk_count: 50000, + }, + }, + ], + ac: [ + { + instance_name: "main", + ac_store: "AC_MAIN_STORE", + }, + ], + + // The capabilities service advertises chunking support; Bazel only + // issues SplitBlob/SpliceBlob when it is advertised. + capabilities: [ + { + instance_name: "main", + }, + ], + bytestream: { + cas_stores: { + main: "CAS_MAIN_STORE", + }, + }, + }, + }, + ], +} diff --git a/nativelink-config/examples/local_rbe_self_test.json5 b/nativelink-config/examples/local_rbe_self_test.json5 new file mode 100644 index 000000000..3e3149bc6 --- /dev/null +++ b/nativelink-config/examples/local_rbe_self_test.json5 @@ -0,0 +1,172 @@ +// A complete NativeLink cluster — CAS, AC, scheduler, and one worker — in a +// single process on localhost. Everything a Bazel client needs (cache AND +// execution) is on one port; nothing here talks to any external service. +// +// Use this to prove your Bazel setup can do remote caching and remote +// execution before you ever point it at a real cluster. See +// docs/rbe/local-remote-execution for the full walkthrough. +// +// Run it: +// nativelink ./nativelink-config/examples/local_rbe_self_test.json5 +// +// Then, from a Bazel workspace: +// bazel test --remote_cache=grpc://127.0.0.1:50051 \ +// --remote_executor=grpc://127.0.0.1:50051 \ +// --remote_default_exec_properties=cpu_count=1 \ +// //some:target +{ + stores: [ + { + name: "CAS_MAIN_STORE", + filesystem: { + content_path: "/tmp/nativelink-local-rbe-test/data/content_path-cas", + temp_path: "/tmp/nativelink-local-rbe-test/data/tmp_path-cas", + eviction_policy: { + max_bytes: 2000000000, + }, + }, + }, + { + name: "AC_MAIN_STORE", + filesystem: { + content_path: "/tmp/nativelink-local-rbe-test/data/content_path-ac", + temp_path: "/tmp/nativelink-local-rbe-test/data/tmp_path-ac", + eviction_policy: { + max_bytes: 200000000, + }, + }, + }, + { + name: "WORKER_FAST_SLOW_STORE", + fast_slow: { + // "fast" must be a filesystem store — the worker hardlinks out of it + // to build each action's sandbox. + fast: { + filesystem: { + content_path: "/tmp/nativelink-local-rbe-test/data/content_path-worker", + temp_path: "/tmp/nativelink-local-rbe-test/data/tmp_path-worker", + eviction_policy: { + max_bytes: 2000000000, + }, + }, + }, + + // The worker and the client-facing CAS share one store instance, so + // whatever the worker produces is immediately visible to Bazel. + slow: { + ref_store: { + name: "CAS_MAIN_STORE", + }, + }, + }, + }, + ], + schedulers: [ + { + name: "MAIN_SCHEDULER", + simple: { + supported_platform_properties: { + cpu_count: "minimum", + OSFamily: "priority", + "container-image": "priority", + }, + }, + }, + ], + workers: [ + { + local: { + worker_api_endpoint: { + uri: "grpc://127.0.0.1:50061", + }, + cas_fast_slow_store: "WORKER_FAST_SLOW_STORE", + upload_action_result: { + ac_store: "AC_MAIN_STORE", + }, + work_directory: "/tmp/nativelink-local-rbe-test/work", + platform_properties: { + cpu_count: { + values: [ + "1", + ], + }, + OSFamily: { + values: [ + "", + ], + }, + "container-image": { + values: [ + "", + ], + }, + }, + + // use_namespaces / use_mount_namespace default to false, which is + // required here — they're Linux-only and this config is meant to + // also run on macOS. + }, + }, + ], + servers: [ + { + // Everything a Bazel client needs — cache AND execution — on one + // local endpoint. No separate/remote cache service involved. + name: "local", + listener: { + http: { + socket_address: "0.0.0.0:50051", + }, + }, + services: { + cas: [ + { + cas_store: "CAS_MAIN_STORE", + }, + ], + ac: [ + { + ac_store: "AC_MAIN_STORE", + }, + ], + bytestream: [ + { + cas_store: "CAS_MAIN_STORE", + }, + ], + execution: [ + { + cas_store: "CAS_MAIN_STORE", + scheduler: "MAIN_SCHEDULER", + }, + ], + capabilities: [ + { + remote_execution: { + scheduler: "MAIN_SCHEDULER", + }, + }, + ], + }, + }, + { + // Workers talk to this port, clients never do — keep it off the + // client-facing listener (see nativelink-config/examples/README.md). + name: "worker_api", + listener: { + http: { + socket_address: "0.0.0.0:50061", + }, + }, + services: { + worker_api: { + scheduler: "MAIN_SCHEDULER", + }, + health: {}, + }, + }, + ], + global: { + max_open_files: 24576, + }, +} diff --git a/nativelink-config/examples/oci_backend.json5 b/nativelink-config/examples/oci_backend.json5 new file mode 100644 index 000000000..496233ad0 --- /dev/null +++ b/nativelink-config/examples/oci_backend.json5 @@ -0,0 +1,186 @@ +// Oracle Cloud Infrastructure (OCI) Object Storage backend via the Amazon S3 +// Compatibility API. +// +// The endpoint is derived from `namespace` + `region` as +// https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com and is +// always addressed path-style (bucket as the first path segment). +// +// Replace the access_key_id / secret_access_key placeholders below with a +// Customer Secret Key (created under User Settings -> Customer secret keys), or +// with shellexpand refs like "${OCI_ACCESS_KEY_ID}". You can also omit both +// placeholders to fall back to the AWS default credential chain (but it only +// reads AWS_* env var names -- your OCI keys would need to live there). +{ + stores: [ + { + name: "CAS_MAIN_STORE", + verify: { + verify_size: true, + backend: { + dedup: { + index_store: { + fast_slow: { + fast: { + memory: { + eviction_policy: { + max_bytes: "100mb", + }, + }, + }, + slow: { + experimental_cloud_object_store: { + provider: "oci", + namespace: "axaxnpcrorw5", + region: "us-phoenix-1", + bucket: "nativelink-cas-test", + access_key_id: "oci_access_key_id", + secret_access_key: "oci_secret_access_key", + key_prefix: "cas-index/", + retry: { + max_retries: 6, + delay: 0.3, + jitter: 0.5, + }, + }, + }, + }, + }, + content_store: { + compression: { + compression_algorithm: { + lz4: {}, + }, + backend: { + fast_slow: { + fast: { + memory: { + eviction_policy: { + max_bytes: "100mb", + }, + }, + }, + slow: { + experimental_cloud_object_store: { + provider: "oci", + namespace: "axaxnpcrorw5", + region: "us-phoenix-1", + bucket: "nativelink-cas-test", + access_key_id: "oci_access_key_id", + secret_access_key: "oci_secret_access_key", + key_prefix: "cas/", + retry: { + max_retries: 6, + delay: 0.3, + jitter: 0.5, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "AC_MAIN_STORE", + fast_slow: { + fast: { + memory: { + eviction_policy: { + max_bytes: "100mb", + }, + }, + }, + slow: { + experimental_cloud_object_store: { + provider: "oci", + namespace: "axaxnpcrorw5", + region: "us-phoenix-1", + bucket: "nativelink-cas-test", + access_key_id: "oci_access_key_id", + secret_access_key: "oci_secret_access_key", + key_prefix: "ac/", + retry: { + max_retries: 6, + delay: 0.3, + jitter: 0.5, + }, + }, + }, + }, + }, + ], + schedulers: [ + { + name: "MAIN_SCHEDULER", + simple: { + supported_platform_properties: { + cpu_count: "minimum", + memory_kb: "minimum", + network_kbps: "minimum", + disk_read_iops: "minimum", + disk_read_bps: "minimum", + disk_write_iops: "minimum", + disk_write_bps: "minimum", + shm_size: "minimum", + gpu_count: "minimum", + gpu_model: "exact", + cpu_vendor: "exact", + cpu_arch: "exact", + cpu_model: "exact", + kernel_version: "exact", + docker_image: "priority", + "lre-rs": "priority", + ISA: "exact", + }, + }, + }, + ], + servers: [ + { + listener: { + http: { + socket_address: "0.0.0.0:50051", + }, + }, + services: { + cas: [ + { + instance_name: "main", + cas_store: "CAS_MAIN_STORE", + }, + ], + ac: [ + { + instance_name: "main", + ac_store: "AC_MAIN_STORE", + }, + ], + execution: [ + { + instance_name: "main", + cas_store: "CAS_MAIN_STORE", + scheduler: "MAIN_SCHEDULER", + }, + ], + capabilities: [ + { + instance_name: "main", + remote_execution: { + scheduler: "MAIN_SCHEDULER", + }, + }, + ], + bytestream: [ + { + instance_name: "main", + cas_store: "CAS_MAIN_STORE", + }, + ], + health: {}, + }, + }, + ], +} diff --git a/nativelink-config/examples/redis.json5 b/nativelink-config/examples/redis.json5 index 082ea6cd6..476ac42a2 100644 --- a/nativelink-config/examples/redis.json5 +++ b/nativelink-config/examples/redis.json5 @@ -6,7 +6,7 @@ addresses: [ "redis://127.0.0.1:6379/", ], - mode: "cluster", + mode: "standard", }, }, { @@ -15,7 +15,7 @@ addresses: [ "redis://127.0.0.1:6379/", ], - mode: "cluster", + mode: "standard", }, }, { diff --git a/nativelink-config/examples/stores-config.json5 b/nativelink-config/examples/stores-config.json5 index 4c6a1b7d3..0748ce406 100644 --- a/nativelink-config/examples/stores-config.json5 +++ b/nativelink-config/examples/stores-config.json5 @@ -85,6 +85,38 @@ }, { name: "6", + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + }, + { + name: "7", + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + }, + { + name: "8", "ontap_s3_existence_cache": { "index_path": "/path/to/cache/index.json", "sync_interval_seconds": 300, @@ -97,7 +129,7 @@ } }, { - name: "7", + name: "9", "verify": { "backend": { "memory": { @@ -111,7 +143,7 @@ } }, { - name: "8", + name: "10", "completeness_checking": { "backend": { "filesystem": { @@ -130,7 +162,7 @@ } }, { - name: "9", + name: "11", "compression": { "compression_algorithm": { "lz4": {} @@ -147,7 +179,7 @@ } }, { - name: "10", + name: "12", "dedup": { "index_store": { "memory": { @@ -186,7 +218,7 @@ } }, { - name: "11", + name: "13", "existence_cache": { "backend": { "memory": { @@ -202,7 +234,7 @@ } }, { - name: "12", + name: "14", "fast_slow": { "fast": { "filesystem": { @@ -225,7 +257,7 @@ } }, { - name: "13", + name: "15", "shard": { "stores": [ { @@ -241,7 +273,7 @@ } }, { - name: "14", + name: "16", "filesystem": { "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", @@ -251,13 +283,13 @@ } }, { - name: "15", + name: "17", "ref_store": { "name": "FS_CONTENT_STORE" } }, { - name: "16", + name: "18", "size_partitioning": { "size": "128mib", "lower_store": { @@ -274,7 +306,7 @@ } }, { - name: "17", + name: "19", "grpc": { "instance_name": "main", "endpoints": [ @@ -295,7 +327,7 @@ } }, { - name: "18", + name: "20", "redis_store": { "addresses": [ "redis://127.0.0.1:6379/", @@ -304,11 +336,11 @@ } }, { - name: "19", + name: "21", "noop": {} }, { - name: "20", + name: "22", "experimental_mongo": { "connection_string": "mongodb://localhost:27017", "database": "nativelink", diff --git a/nativelink-config/src/cas_server.rs b/nativelink-config/src/cas_server.rs index 5015e9aea..727830b59 100644 --- a/nativelink-config/src/cas_server.rs +++ b/nativelink-config/src/cas_server.rs @@ -18,15 +18,18 @@ use nativelink_error::{Code, Error, ResultExt, make_err}; #[cfg(feature = "dev-schema")] use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use tracing::warn; use crate::schedulers::SchedulerSpec; use crate::serde_utils::{ - convert_data_size_with_shellexpand, convert_duration_with_shellexpand, - convert_numeric_with_shellexpand, convert_optional_numeric_with_shellexpand, - convert_optional_string_with_shellexpand, convert_string_with_shellexpand, - convert_vec_string_with_shellexpand, + convert_boolean_with_shellexpand, convert_data_size_with_shellexpand, + convert_duration_with_shellexpand, convert_numeric_with_shellexpand, + convert_optional_numeric_with_shellexpand, convert_optional_string_with_shellexpand, + convert_string_with_shellexpand, convert_vec_string_with_shellexpand, +}; +use crate::stores::{ + ClientTlsConfig, ConfigDigestHashFunction, StoreRefName, StoreSpec, StoreType, }; -use crate::stores::{ClientTlsConfig, ConfigDigestHashFunction, StoreRefName, StoreSpec}; /// Name of the scheduler. This type will be used when referencing a /// scheduler in the `CasConfig::schedulers`'s map key. @@ -121,7 +124,7 @@ pub struct AcStoreConfig { pub read_only: bool, } -#[derive(Deserialize, Serialize, Debug)] +#[derive(Deserialize, Serialize, Debug, Clone)] #[serde(deny_unknown_fields)] #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] pub struct CasStoreConfig { @@ -129,6 +132,115 @@ pub struct CasStoreConfig { /// This store name referenced here may be reused multiple times. #[serde(deserialize_with = "convert_string_with_shellexpand")] pub cas_store: StoreRefName, + + /// Optional and experimental: enables the REAPI `SplitBlob`/`SpliceBlob` + /// RPCs used by content-defined chunking clients (e.g. Bazel's + /// `--experimental_remote_cache_chunking`). When set, the capabilities + /// service advertises blob split/splice support and `FastCDC` 2020 + /// parameters for this instance. When `cas_store` is a grpc store the + /// RPCs are forwarded to the backend (which must support chunking with + /// matching parameters); otherwise they are served locally. + /// + /// See `nativelink-config/examples/chunking_cas.json5` for a complete + /// configuration example. + /// + /// Default: not set — chunking RPCs are rejected, nothing is advertised, + /// and behavior is identical to when this option did not exist. + #[serde(default)] + pub experimental_chunking: Option, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(deny_unknown_fields)] +#[cfg_attr(feature = "dev-schema", derive(JsonSchema))] +pub struct CasChunkingConfig { + /// The store name referenced in the `stores` map in the main config used + /// to persist blob-to-chunks layouts. Keys are the digests of the + /// original blobs and values are serialized chunk layouts (which do not + /// hash to those digests), so this store MUST NOT perform content digest + /// verification and MUST NOT be the same store as `cas_store` — writing + /// layouts into the CAS would overwrite blob content. Using the same + /// store name as `cas_store` is rejected at startup. + /// + /// Required unless `cas_store` is a grpc store: for proxied instances + /// the `SplitBlob`/`SpliceBlob` RPCs are forwarded to the backend, which + /// owns the chunk layouts, and setting an `index_store` is rejected at + /// startup. + #[serde(default, deserialize_with = "convert_optional_string_with_shellexpand")] + pub index_store: Option, + + /// The average chunk size in bytes advertised to clients through the + /// `FastCDC` 2020 capability parameters and used for server-side + /// chunking in `SplitBlob`. Clients derive the minimum and maximum + /// chunk sizes from this value (avg / 4 and avg * 4). The value must + /// be between 1 KiB and 1 MiB. + /// + /// Default: 524288 (512 KiB) + #[serde(default)] + pub avg_chunk_size_bytes: u64, + + /// Maximum number of chunks accepted in a `SpliceBlob` request or + /// produced by on-demand chunking in `SplitBlob`. Blobs that would + /// produce more chunks are served without chunking (`SplitBlob` returns + /// `NOT_FOUND` and clients fall back to a regular download). This bounds + /// the size of stored chunk layouts and of `SplitBlobResponse` messages + /// (roughly 80-140 bytes per chunk). At the default average chunk size + /// the default cap supports blobs up to ~25 GiB; note that values above + /// ~50000 may produce responses that exceed default gRPC message size + /// limits on clients. + /// + /// Default: 50000 + #[serde(default)] + pub max_chunk_count: u64, +} + +impl CasChunkingConfig { + /// Default for `avg_chunk_size_bytes`, the value recommended by the + /// REAPI spec for `FastCdc2020Params`. + pub const DEFAULT_AVG_CHUNK_SIZE_BYTES: u64 = 512 * 1024; + /// Bounds for `avg_chunk_size_bytes` mandated by the REAPI spec for + /// `FastCdc2020Params`. + pub const MIN_AVG_CHUNK_SIZE_BYTES: u64 = 1024; + pub const MAX_AVG_CHUNK_SIZE_BYTES: u64 = 1024 * 1024; + /// Default for `max_chunk_count`. + pub const DEFAULT_MAX_CHUNK_COUNT: u64 = 50_000; + + /// Returns `avg_chunk_size_bytes` with the default applied. + #[must_use] + pub const fn resolved_avg_chunk_size_bytes(&self) -> u64 { + if self.avg_chunk_size_bytes == 0 { + Self::DEFAULT_AVG_CHUNK_SIZE_BYTES + } else { + self.avg_chunk_size_bytes + } + } + + /// Returns `max_chunk_count` with the default applied. + #[must_use] + pub const fn resolved_max_chunk_count(&self) -> u64 { + if self.max_chunk_count == 0 { + Self::DEFAULT_MAX_CHUNK_COUNT + } else { + self.max_chunk_count + } + } + + /// Returns `avg_chunk_size_bytes` with the default applied, or an error + /// when the configured value is outside the REAPI-mandated bounds. + pub fn validated_avg_chunk_size_bytes(&self) -> Result { + let avg_chunk_size_bytes = self.resolved_avg_chunk_size_bytes(); + if !(Self::MIN_AVG_CHUNK_SIZE_BYTES..=Self::MAX_AVG_CHUNK_SIZE_BYTES) + .contains(&avg_chunk_size_bytes) + { + return Err(make_err!( + Code::InvalidArgument, + "'experimental_chunking.avg_chunk_size_bytes' is {avg_chunk_size_bytes}, must be between {} and {}", + Self::MIN_AVG_CHUNK_SIZE_BYTES, + Self::MAX_AVG_CHUNK_SIZE_BYTES + )); + } + Ok(avg_chunk_size_bytes) + } } #[derive(Deserialize, Serialize, Debug, Default)] @@ -148,6 +260,18 @@ pub struct CapabilitiesConfig { /// If not set the capabilities service will inform the client that remote /// execution is not supported. pub remote_execution: Option, + + /// Whether this instance supports Bazel remote cache compression. + /// When enabled, the capabilities service advertises zstd wire compression + /// and the ByteStream/CAS services accept REAPI compressed-blobs/zstd data. + /// + /// Bazel clients enable this with `--remote_cache_compression`. + #[serde( + default, + skip_serializing_if = "is_default", + deserialize_with = "convert_boolean_with_shellexpand" + )] + pub remote_cache_compression: bool, } #[derive(Deserialize, Serialize, Debug)] @@ -231,7 +355,7 @@ pub struct ByteStreamConfig { } // Older bytestream config. All fields are as per the newer docs, but this requires -// the hashed cas_stores v.s. the WithInstanceName approach. This should _not_ be updated +// the hashed `cas_stores` v.s. the WithInstanceName approach. This should _not_ be updated // with newer fields, and eventually dropped #[derive(Deserialize, Serialize, Debug, Clone)] #[serde(deny_unknown_fields)] @@ -367,7 +491,7 @@ pub struct ServicesConfig { /// Capabilities service is required in order to use most of the /// bazel protocol. This service is used to provide the supported - /// features and versions of this bazel GRPC service. + /// features and versions of this bazel gRPC service. #[serde( default, deserialize_with = "super::backcompat::opt_vec_with_instance_name" @@ -757,7 +881,7 @@ pub struct UploadActionResultConfig { pub struct LocalWorkerConfig { /// Name of the worker. This is give a more friendly name to a worker for logging /// and metric publishing. This is also the prefix of the worker id - /// (ie: "{name}{uuidv6}"). + /// (i.e. "{name}{uuidv6}"). /// Default: {Index position in the workers list} #[serde(default, deserialize_with = "convert_string_with_shellexpand")] pub name: String, @@ -873,7 +997,7 @@ pub struct LocalWorkerConfig { pub platform_properties: HashMap, /// An optional mapping of environment names to set for the execution - /// as well as those specified in the action itself. If set, will set each + /// as well as those specified in the action itself. If set, will set each /// key as an environment variable before executing the job with the value /// of the environment variable being the value of the property of the /// action being executed of that name or the fixed value. @@ -885,9 +1009,26 @@ pub struct LocalWorkerConfig { /// Default: None (directory cache disabled) pub directory_cache: Option, - /// Whether to use namespaces to isolate the execution. This is only available - /// on Linux. It is highly recommended as it avoids a number of issues with - /// zombie processes and also provides additional hermeticity. If explicitly set + /// Optional and experimental: lease every digest in an active action's + /// input Merkle closure in the worker's locally eviction-managed CAS + /// tiers (the `cas_fast_slow_store`'s filesystem-backed stores) until the + /// action has finished cleanup. This prevents `Lost inputs no longer + /// available remotely` failures caused by local fast-tier eviction while + /// inputs are being materialized under cache pressure. + /// + /// Trade-off: while leases are held, a local filesystem tier may + /// temporarily exceed its configured `max_bytes` / `max_count` eviction + /// limits; normal eviction resumes once the action's leases are released. + /// Operators should leave headroom on the underlying disk when enabling + /// this. + /// + /// Default: false (eviction behavior is unchanged) + #[serde(default)] + pub experimental_active_input_leases: bool, + + /// Whether to use namespaces to isolate the execution. This is only available + /// on Linux. It is highly recommended as it avoids a number of issues with + /// zombie processes and also provides additional hermeticity. If explicitly set /// to true and it is not supported the worker will exit with an error. /// /// Note: this will fail for non-privileged Dockerised workers, as workers in @@ -897,9 +1038,9 @@ pub struct LocalWorkerConfig { /// Default: False. pub use_namespaces: Option, - /// Whether to use a mount namespace to isolate the worker root. This is only - /// available on Linux and when `use_namespaces` is true. It is highly recommended - /// provides additional hermeticity. If explicitly set to true and it is not + /// Whether to use a mount namespace to isolate the worker root. This is only + /// available on Linux and when `use_namespaces` is true. It is highly recommended + /// provides additional hermeticity. If explicitly set to true and it is not /// supported or `use_namespaces` is not set to true the worker will exit with an /// error. /// Default: False. @@ -928,12 +1069,76 @@ pub struct DirectoryCacheConfig { /// Default: `{work_directory}/../directory_cache` #[serde(default, deserialize_with = "convert_string_with_shellexpand")] pub cache_root: String, + + /// Optional and experimental: additionally cache every subdirectory by + /// its own `Directory` digest, not just the root directory. REAPI Merkle + /// nodes are content-addressed, so a subtree that is byte-identical + /// between two different roots has the same digest and can be + /// materialized with a single hardlink pass instead of being rebuilt + /// from the CAS. This makes the common "one input file changed out of + /// thousands" case reuse every unchanged subtree. + /// + /// Note: subtree caching multiplies the entry COUNT in the cache (every + /// distinct subdirectory becomes its own entry, subject to the normal + /// eviction budgets), so operators enabling this should raise + /// `max_entries` accordingly (for example 10x). To avoid multiplying the + /// SIZE accounting too, an entry's recorded size covers only bytes not + /// owned by a descendant entry, so the cache's size total approximates + /// unique materialized bytes rather than counting each file once per + /// ancestor level. + /// + /// Trade-off: cold constructions pay roughly one extra hardlink pass per + /// tree level (measured ~10% cold overhead at depth 3, within run + /// variance) in exchange for the churn-path reuse above. + /// + /// Default: false (only root directories are cached; existing behavior) + #[serde(default)] + pub experimental_subtree_caching: bool, + + /// Maximum number of concurrent slow-store fetches across ALL directory + /// constructions of this cache. This bound protects backing stores from + /// RPC storms: per-level construction concurrency compounds + /// multiplicatively across tree levels and concurrent actions. + /// + /// Interaction with read coalescing: this semaphore fragments coalesced + /// batches to at most this many items and serializes fetch waves for + /// trees with many tiny files. Deployments using + /// `experimental_read_batching` on the underlying grpc store can raise + /// this substantially (for example 512), since batching collapses the + /// RPC count. Must be greater than 0. + /// + /// Default: 64 + #[serde(default = "default_directory_cache_max_concurrent_fetches")] + pub max_concurrent_fetches: usize, + /// On a directory-cache miss, prefetch every `Directory` proto of the + /// tree with one logical `GetTree` traversal instead of fetching protos + /// level by level (which costs one round trip per tree DEPTH). The + /// [REAPI request contract] permits servers to impose their own limit even + /// when no page size is specified, and the [REAPI response contract] + /// requires clients to continue with the returned page token. A paginated + /// traversal may therefore use multiple RPCs. Only takes effect when the + /// slow tier is a `grpc` store; + /// any prefetch failure falls back to the per-level path. Worthwhile when + /// worker-to-CAS latency is non-trivial and trees are deep; measured 5-34x + /// on the proto phase at 5-25ms RTT. Note the serving CAS pays the tree walk + /// against its own backend, so its directory protos should be served + /// from a fast tier. + /// + /// [REAPI request contract]: https://github.com/bazelbuild/remote-apis/blob/becdd8f9ff811df88a22d3eadd6341753d51d167/build/bazel/remote/execution/v2/remote_execution.proto#L1932-L1942 + /// [REAPI response contract]: https://github.com/bazelbuild/remote-apis/blob/becdd8f9ff811df88a22d3eadd6341753d51d167/build/bazel/remote/execution/v2/remote_execution.proto#L1961-L1965 + /// Default: false + #[serde(default)] + pub experimental_get_tree_prefetch: bool, } const fn default_directory_cache_max_entries() -> usize { 1000 } +const fn default_directory_cache_max_concurrent_fetches() -> usize { + 64 +} + const fn default_directory_cache_max_size_bytes() -> u64 { 10 * 1024 * 1024 * 1024 // 10 GB } @@ -1011,21 +1216,93 @@ pub struct CasConfig { } impl CasConfig { + const ZSTD_COMPRESSION_DOCS_URL: &'static str = + "https://docs.nativelink.com/configuration/compression"; + /// # Errors /// /// Will return `Err` if we can't load the file. pub fn try_from_json5_file(config_file: &str) -> Result { let json_contents = std::fs::read_to_string(config_file) .err_tip(|| format!("Could not open config file {config_file}"))?; - let config: Self = serde_json5::from_str(&json_contents)?; + Self::try_from_json5_str(&json_contents) + } + + fn try_from_json5_str(json_contents: &str) -> Result { + let mut config: Self = serde_json5::from_str(json_contents)?; for server in &config.servers { if let Some(services) = &server.services { Self::check_store_conflict(services)?; } } + config.apply_zstd_grpc_store_defaults(); Ok(config) } + fn zstd_wire_compression_enabled_anywhere(&self) -> bool { + if self + .servers + .iter() + .filter_map(|server| server.services.as_ref()) + .filter_map(|services| services.capabilities.as_deref()) + .flatten() + .any(|capabilities| capabilities.remote_cache_compression) + { + return true; + } + + self.stores.iter().any(|store| { + let mut enabled = false; + store.spec.visit_grpc_specs(&mut |grpc| { + enabled |= matches!(grpc.store_type, StoreType::Cas) + && grpc.experimental_remote_cache_compression == Some(true); + }); + enabled + }) + } + + fn apply_zstd_grpc_store_defaults(&mut self) { + let zstd_enabled_anywhere = self.zstd_wire_compression_enabled_anywhere(); + + for store in &mut self.stores { + let store_name = store.name.as_str(); + store.spec.visit_grpc_specs_mut(&mut |grpc| { + if !matches!(grpc.store_type, StoreType::Cas) { + if grpc.experimental_remote_cache_compression == Some(true) { + warn!( + store = store_name, + instance_name = grpc.instance_name, + "'experimental_remote_cache_compression' is enabled on a non-CAS \ + gRPC store, where it has no effect: REAPI zstd wire compression \ + only applies to CAS blob transfers. Enable it on the CAS gRPC \ + stores or a capabilities instance instead. See {}", + Self::ZSTD_COMPRESSION_DOCS_URL, + ); + } + return; + } + + if !zstd_enabled_anywhere { + return; + } + + match grpc.experimental_remote_cache_compression { + None => grpc.experimental_remote_cache_compression = Some(true), + Some(false) => warn!( + store = store_name, + instance_name = grpc.instance_name, + "Zstd wire compression is enabled elsewhere, but this eligible CAS gRPC \ + store explicitly disables it. Unless this upstream cannot use zstd, \ + enable 'experimental_remote_cache_compression' for substantially faster \ + transfers of compressible artifacts. See {}", + Self::ZSTD_COMPRESSION_DOCS_URL, + ), + Some(true) => {} + } + }); + } + } + fn check_store_conflict(services: &ServicesConfig) -> Result<(), Error> { if let Some(cas_config) = &services.cas && let Some(ac_config) = &services.ac @@ -1056,3 +1333,199 @@ impl CasConfig { Ok(()) } } + +#[cfg(test)] +mod tests { + use tracing_test::traced_test; + + use super::*; + + fn grpc_compression_configs(config: &CasConfig) -> Vec<(bool, Option)> { + let mut configs = Vec::new(); + for store in &config.stores { + store.spec.visit_grpc_specs(&mut |grpc| { + configs.push(( + matches!(grpc.store_type, StoreType::Cas), + grpc.experimental_remote_cache_compression, + )); + }); + } + configs + } + + #[test] + fn capabilities_config_remote_cache_compression_deserializes_true() { + let config: CapabilitiesConfig = + serde_json5::from_str(r#"{"remote_cache_compression": true}"#).unwrap(); + + assert!(config.remote_cache_compression); + } + + #[test] + fn capabilities_config_remote_cache_compression_defaults_false() { + let config: CapabilitiesConfig = serde_json5::from_str("{}").unwrap(); + + assert!(!config.remote_cache_compression); + } + + #[test] + fn omitted_grpc_compression_stays_disabled_without_zstd_intent() { + let config = CasConfig::try_from_json5_str( + r#"{ + stores: [{ + name: "upstream", + grpc: { + endpoints: [{ address: "http://localhost:1234" }], + store_type: "cas", + }, + }], + servers: [], + }"#, + ) + .unwrap(); + + assert_eq!(grpc_compression_configs(&config), vec![(true, None)]); + } + + #[test] + fn explicit_grpc_zstd_intent_enables_other_eligible_grpc_stores() { + let config = CasConfig::try_from_json5_str( + r#"{ + stores: [ + { + name: "enabled", + grpc: { + endpoints: [{ address: "http://localhost:1234" }], + store_type: "cas", + experimental_remote_cache_compression: true, + }, + }, + { + name: "inherited", + grpc: { + endpoints: [{ address: "http://localhost:5678" }], + store_type: "cas", + }, + }, + ], + servers: [], + }"#, + ) + .unwrap(); + + assert_eq!( + grpc_compression_configs(&config), + vec![(true, Some(true)), (true, Some(true))] + ); + } + + #[test] + #[traced_test] + fn ac_grpc_compression_warns_and_expresses_no_cas_intent() { + let config = CasConfig::try_from_json5_str( + r#"{ + stores: [ + { + name: "action-cache", + grpc: { + instance_name: "ac", + endpoints: [{ address: "http://localhost:1234" }], + store_type: "ac", + experimental_remote_cache_compression: true, + }, + }, + { + name: "cas", + grpc: { + endpoints: [{ address: "http://localhost:5678" }], + store_type: "cas", + }, + }, + ], + servers: [], + }"#, + ) + .unwrap(); + + // The AC-store setting is inert: it neither compresses AC RPCs nor + // expresses process-wide zstd intent, so the CAS store stays unset. + assert_eq!( + grpc_compression_configs(&config), + vec![(false, Some(true)), (true, None)] + ); + assert!(logs_contain("store=\"action-cache\"")); + assert!(logs_contain("no effect")); + } + + #[test] + #[traced_test] + fn capabilities_zstd_intent_defaults_nested_cas_grpc_and_warns_on_opt_out() { + let config = CasConfig::try_from_json5_str( + r#"{ + stores: [{ + name: "nested-upstreams", + fast_slow: { + fast: { + grpc: { + instance_name: "auto", + endpoints: [{ address: "http://localhost:1234" }], + store_type: "cas", + }, + }, + slow: { + shard: { + stores: [ + { + store: { + grpc: { + instance_name: "opt-out", + endpoints: [{ + address: "http://localhost:5678", + }], + store_type: "cas", + experimental_remote_cache_compression: false, + }, + }, + weight: 1, + }, + { + store: { + grpc: { + instance_name: "action-cache", + endpoints: [{ + address: "http://localhost:9012", + }], + store_type: "ac", + }, + }, + weight: 1, + }, + ], + }, + }, + }, + }], + servers: [{ + listener: { + http: { socket_address: "127.0.0.1:50051" }, + }, + services: { + capabilities: [{ + instance_name: "main", + remote_cache_compression: true, + }], + }, + }], + }"#, + ) + .unwrap(); + + assert_eq!( + grpc_compression_configs(&config), + vec![(true, Some(true)), (true, Some(false)), (false, None),] + ); + assert!(logs_contain("store=\"nested-upstreams\"")); + assert!(logs_contain("instance_name=\"opt-out\"")); + assert!(logs_contain(CasConfig::ZSTD_COMPRESSION_DOCS_URL)); + } +} diff --git a/nativelink-config/src/schedulers.rs b/nativelink-config/src/schedulers.rs index 3d32c9f33..3b840e545 100644 --- a/nativelink-config/src/schedulers.rs +++ b/nativelink-config/src/schedulers.rs @@ -83,6 +83,11 @@ const fn default_worker_match_logging_interval_s() -> i64 { 10 } +// defaults to every 5s +const fn default_fallback_match_interval_s() -> i64 { + 5 +} + #[derive(Deserialize, Serialize, Debug, Default)] #[serde(deny_unknown_fields)] #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] @@ -100,7 +105,7 @@ pub struct SimpleSpec { /// { "cpu_count": "8", "cpu_arch": "arm" } /// ``` /// Will result in the scheduler filtering out any workers that do not have - /// `"cpu_arch" = "arm"` and filter out any workers that have less than 8 cpu + /// `"cpu_arch" = "arm"` and filter out any workers that have less than 8 CPU /// cores available. /// /// The property names here must match the property keys provided by the @@ -108,7 +113,7 @@ pub struct SimpleSpec { /// publish their capabilities to the scheduler when they join the worker /// pool. If the worker fails to notify the scheduler of its (for example) /// `"cpu_arch"`, the scheduler will never send any jobs to it, if all jobs - /// have the `"cpu_arch"` label. There is no special treatment of any platform + /// have the `"cpu_arch"` label. We have no special treatment of any platform /// property labels other and entirely driven by worker configs and this /// config. pub supported_platform_properties: Option>, @@ -167,6 +172,20 @@ pub struct SimpleSpec { deserialize_with = "convert_duration_with_shellexpand_and_negative" )] pub worker_match_logging_interval_s: i64, + + /// Every N seconds, run a worker matching pass even if no task or worker + /// change notification arrived. This is a safety net for missed + /// notifications and for scheduler backends with eventually consistent + /// searches (for example Redis), where an operation that was re-queued + /// may not be visible to the search triggered by its own notification. + /// Without this, such an operation can stay queued until an unrelated + /// event triggers another matching pass. + /// Defaults to 5s. Zero or any negative value disables it. + #[serde( + default = "default_fallback_match_interval_s", + deserialize_with = "convert_duration_with_shellexpand_and_negative" + )] + pub fallback_match_interval_s: i64, } #[derive(Deserialize, Serialize, Debug)] @@ -188,9 +207,9 @@ pub struct ExperimentalRedisSchedulerBackend { pub redis_store: StoreRefName, } -/// A scheduler that simply forwards requests to an upstream scheduler. This +/// A scheduler that forwards requests to an upstream scheduler. This /// is useful to use when doing some kind of local action cache or CAS away from -/// the main cluster of workers. In general, it's more efficient to point the +/// the main cluster of workers. In general, it's more efficient to point the /// build at the main scheduler directly though. #[derive(Deserialize, Serialize, Debug)] #[serde(deny_unknown_fields)] @@ -203,8 +222,8 @@ pub struct GrpcSpec { #[serde(default)] pub retry: Retry, - /// Limit the number of simultaneous upstream requests to this many. A - /// value of zero is treated as unlimited. If the limit is reached the + /// Limit the number of simultaneous upstream requests to this many. A + /// value of zero is treated as unlimited. If the limit is reached the /// request is queued. /// Default: unlimited #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] @@ -246,7 +265,7 @@ pub struct PlatformPropertyAddition { pub struct PlatformPropertyReplacement { /// The name of the property to replace. pub name: String, - /// The the value to match against, if unset then any instance matches. + /// The value to match against, if unset then any instance matches. #[serde(default)] pub value: Option, /// The new name of the property. @@ -273,9 +292,9 @@ pub enum PropertyModification { #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] pub struct PropertyModifierSpec { /// A list of modifications to perform to incoming actions for the nested - /// scheduler. These are performed in order and blindly, so removing a + /// scheduler. These are performed in order and blindly, so removing a /// property that doesn't exist is fine and overwriting an existing property - /// is also fine. If adding properties that do not exist in the nested + /// is also fine. If adding properties that do not exist in the nested /// scheduler is not supported and will likely cause unexpected behaviour. pub modifications: Vec, diff --git a/nativelink-config/src/stores.rs b/nativelink-config/src/stores.rs index d8b7f473d..b8e827492 100644 --- a/nativelink-config/src/stores.rs +++ b/nativelink-config/src/stores.rs @@ -153,8 +153,8 @@ pub enum StoreSpec { /// } /// ``` /// - /// 4. **`NetApp` ONTAP S3** - /// `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend + /// 4. **NetApp ONTAP S3:** + /// NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend /// to store files. This store is specifically configured for ONTAP's S3 requirements /// including custom TLS configuration, credentials management, and proper vserver /// configuration. @@ -181,6 +181,55 @@ pub enum StoreSpec { /// "multipart_max_concurrent_uploads": 10 /// } /// ``` + /// + /// 5. **Cloudflare R2:** + /// R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + /// S3 API, so this is a thin wrapper that derives the account-scoped + /// endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + /// + /// **Example JSON Config:** + /// ```json + /// "experimental_cloud_object_store": { + /// "provider": "r2", + /// "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + /// "bucket": "nativelink-cas", + /// "key_prefix": "test-prefix/", + /// "retry": { + /// "max_retries": 6, + /// "delay": 0.3, + /// "jitter": 0.5 + /// }, + /// "multipart_max_concurrent_uploads": 10 + /// } + /// ``` + /// + /// 6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + /// OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + /// Storage API. The path-style endpoint is derived from your Object + /// Storage `namespace` and `region` as + /// `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + /// Authenticate with a Customer Secret Key (Access Key/Secret Key pair + /// created under User Settings -> Customer secret keys in the OCI + /// console); the secret cannot be retrieved after generation, so read + /// it from an env var via shellexpand. + /// + /// **Example JSON Config:** + /// ```json + /// "experimental_cloud_object_store": { + /// "provider": "oci", + /// "namespace": "your-object-storage-namespace", + /// "region": "us-phoenix-1", + /// "bucket": "nativelink-cas", + /// "access_key_id": "oci_access_key_id", + /// "secret_access_key": "oci_secret_access_key", + /// "key_prefix": "test-prefix/", + /// "retry": { + /// "max_retries": 6, + /// "delay": 0.3, + /// "jitter": 0.5 + /// } + /// } + /// ``` ExperimentalCloudObjectStore(ExperimentalCloudObjectSpec), /// ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store @@ -389,7 +438,7 @@ pub enum StoreSpec { /// WARNING: If you need data to always exist in the `slow` store /// for something like remote execution, be careful because this /// store will never check to see if the objects exist in the - /// `slow` store if it exists in the `fast` store (ie: it assumes + /// `slow` store if it exists in the `fast` store (i.e. it assumes /// that if an object exists in the `fast` store it will exist in /// the `slow` store). /// @@ -482,7 +531,7 @@ pub enum StoreSpec { /// used if the size field is the real size of the content, in other /// words, don't use on AC (Action Cache) stores. Any store where you can /// safely use `VerifySpec.verify_size = true`, this store should be safe - /// to use (ie: CAS stores). + /// to use (i.e. CAS stores). /// /// **Example JSON Config:** /// ```json @@ -504,7 +553,7 @@ pub enum StoreSpec { /// SizePartitioning(Box), - /// This store will pass-through calls to another GRPC store. This store + /// This store will pass-through calls to another gRPC store. This store /// is not designed to be used as a sub-store of another store, but it /// does satisfy the interface and will likely work. /// @@ -544,6 +593,12 @@ pub enum StoreSpec { /// Ideal for accepting small object sizes as most redis store /// services have a max file upload of between 256Mb-512Mb. /// + /// If you are using Redis together with any stores above it + /// e.g. existence cache, you will need to configure `notify-keyspace-events` + /// to `KA` as per + /// in order for us to get eviction events. Failing to do so will get you + /// log messages complaining about it, as well as errors like + /// /// **Example JSON Config:** /// ```json /// "redis_store": { @@ -591,6 +646,86 @@ pub enum StoreSpec { ExperimentalMongo(ExperimentalMongoSpec), } +impl StoreSpec { + pub(crate) fn visit_grpc_specs(&self, visitor: &mut dyn FnMut(&GrpcSpec)) { + match self { + Self::CacheMetrics(spec) => spec.backend.visit_grpc_specs(visitor), + Self::Verify(spec) => spec.backend.visit_grpc_specs(visitor), + Self::Compression(spec) => spec.backend.visit_grpc_specs(visitor), + Self::Dedup(spec) => { + spec.index_store.visit_grpc_specs(visitor); + spec.content_store.visit_grpc_specs(visitor); + } + Self::ExistenceCache(spec) => spec.backend.visit_grpc_specs(visitor), + Self::CompletenessChecking(spec) => { + spec.backend.visit_grpc_specs(visitor); + spec.cas_store.visit_grpc_specs(visitor); + } + Self::FastSlow(spec) => { + spec.fast.visit_grpc_specs(visitor); + spec.slow.visit_grpc_specs(visitor); + } + Self::Shard(spec) => { + for shard in &spec.stores { + shard.store.visit_grpc_specs(visitor); + } + } + Self::SizePartitioning(spec) => { + spec.lower_store.visit_grpc_specs(visitor); + spec.upper_store.visit_grpc_specs(visitor); + } + Self::Grpc(spec) => visitor(spec), + Self::Memory(_) + | Self::ExperimentalCloudObjectStore(_) + | Self::OntapS3ExistenceCache(_) + | Self::Filesystem(_) + | Self::RefStore(_) + | Self::RedisStore(_) + | Self::Noop(_) + | Self::ExperimentalMongo(_) => {} + } + } + + pub(crate) fn visit_grpc_specs_mut(&mut self, visitor: &mut dyn FnMut(&mut GrpcSpec)) { + match self { + Self::CacheMetrics(spec) => spec.backend.visit_grpc_specs_mut(visitor), + Self::Verify(spec) => spec.backend.visit_grpc_specs_mut(visitor), + Self::Compression(spec) => spec.backend.visit_grpc_specs_mut(visitor), + Self::Dedup(spec) => { + spec.index_store.visit_grpc_specs_mut(visitor); + spec.content_store.visit_grpc_specs_mut(visitor); + } + Self::ExistenceCache(spec) => spec.backend.visit_grpc_specs_mut(visitor), + Self::CompletenessChecking(spec) => { + spec.backend.visit_grpc_specs_mut(visitor); + spec.cas_store.visit_grpc_specs_mut(visitor); + } + Self::FastSlow(spec) => { + spec.fast.visit_grpc_specs_mut(visitor); + spec.slow.visit_grpc_specs_mut(visitor); + } + Self::Shard(spec) => { + for shard in &mut spec.stores { + shard.store.visit_grpc_specs_mut(visitor); + } + } + Self::SizePartitioning(spec) => { + spec.lower_store.visit_grpc_specs_mut(visitor); + spec.upper_store.visit_grpc_specs_mut(visitor); + } + Self::Grpc(spec) => visitor(spec), + Self::Memory(_) + | Self::ExperimentalCloudObjectStore(_) + | Self::OntapS3ExistenceCache(_) + | Self::Filesystem(_) + | Self::RefStore(_) + | Self::RedisStore(_) + | Self::Noop(_) + | Self::ExperimentalMongo(_) => {} + } + } +} + /// Configuration for an individual shard of the store. #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] @@ -658,7 +793,7 @@ pub struct RefSpec { pub struct FilesystemSpec { /// Path on the system where to store the actual content. This is where /// the bulk of the data will be placed. - /// On service bootup this folder will be scanned and all files will be + /// On service boot this folder will be scanned and all files will be /// added to the cache. In the event one of the files doesn't match the /// criteria, the file will be deleted. #[serde(deserialize_with = "convert_string_with_shellexpand")] @@ -667,7 +802,7 @@ pub struct FilesystemSpec { /// A temporary location of where files that are being uploaded or /// deleted will be placed while the content cannot be guaranteed to be /// accurate. This location must be on the same block device as - /// `content_path` so atomic moves can happen (ie: move without copy). + /// `content_path` so atomic moves can happen (i.e. move without copy). /// All files in this folder will be deleted on every startup. #[serde(deserialize_with = "convert_string_with_shellexpand")] pub temp_path: String, @@ -699,6 +834,16 @@ pub struct FilesystemSpec { /// Default: unlimited #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] pub max_concurrent_writes: usize, + + /// When true, advise the kernel to drop the page cache for each blob after + /// it is written or read (`posix_fadvise` with `POSIX_FADV_DONTNEED`). On + /// real filesystems this takes a globally serialized, all-CPU kernel path + /// that stalls on many-core hosts, and it evicts the page-cache tier that + /// fast-disk deployments rely on. Leave off unless you specifically want to + /// keep this store's I/O out of the page cache. + /// Default: false + #[serde(default)] + pub evict_page_cache: bool, } // NetApp ONTAP S3 Spec @@ -747,6 +892,53 @@ pub struct ExperimentalR2Spec { pub common: CommonObjectSpec, } +// Oracle Cloud Infrastructure (OCI) Object Storage Spec. +// +// Uses the OCI Object Storage Amazon S3 Compatibility API. The store talks to +// the path-style compatibility endpoint, which embeds the Object Storage +// namespace in the host and the bucket in the request path: +// `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com/{bucket}/{object}`. +// Authentication uses a Customer Secret Key (an Access Key/Secret Key pair +// generated under User Settings in the OCI console) signed with AWS SigV4. +#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[serde(deny_unknown_fields)] +#[cfg_attr(feature = "dev-schema", derive(JsonSchema))] +pub struct ExperimentalOciSpec { + /// OCI Object Storage namespace. This is the immutable, system-generated + /// top-level container assigned to the tenancy (the same name in every + /// region). It is the host prefix of the derived path-style endpoint: + /// `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + #[serde(deserialize_with = "convert_string_with_shellexpand")] + pub namespace: String, + + /// OCI region identifier, for example `us-phoenix-1` or `us-ashburn-1`. + /// Used both to build the endpoint host and as the AWS `SigV4` signing + /// region. If your tooling cannot set an OCI region identifier, OCI also + /// accepts `us-east-1` to target the tenancy home region. + #[serde(deserialize_with = "convert_string_with_shellexpand")] + pub region: String, + + /// Bucket name to use as the backend. Bucket names must be unique within + /// the Object Storage namespace. + #[serde(deserialize_with = "convert_string_with_shellexpand")] + pub bucket: String, + + /// Customer Secret Key access key. When omitted (along with + /// `secret_access_key`), the default AWS credential chain is used instead. + #[serde(default, deserialize_with = "convert_optional_string_with_shellexpand")] + pub access_key_id: Option, + + /// Customer Secret Key secret. OCI does not allow retrieving a secret key + /// after generation, so store it securely (for example via `${ENV_VAR}` + /// shell expansion). + #[serde(default, deserialize_with = "convert_optional_string_with_shellexpand")] + pub secret_access_key: Option, + + /// Retry and upload settings. + #[serde(flatten)] + pub common: CommonObjectSpec, +} + #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] @@ -787,7 +979,7 @@ pub struct FastSlowSpec { /// out to the `slow` store. pub fast: StoreSpec, - /// How to handle the fast store. This can be useful to set to Get for + /// How to handle the fast store. This can be useful to set to Get for /// worker nodes such that results are persisted to the slow store only. #[serde(default)] pub fast_direction: StoreDirection, @@ -796,7 +988,7 @@ pub struct FastSlowSpec { /// get it from this store. pub slow: StoreSpec, - /// How to handle the slow store. This can be useful if creating a diode + /// How to handle the slow store. This can be useful if creating a diode /// and you wish to have an upstream read only store. #[serde(default)] pub slow_direction: StoreDirection, @@ -867,7 +1059,7 @@ pub struct DedupSpec { /// Due to implementation detail, we want to prefer to download /// the first chunks of the file so we can stream the content /// out and free up some of our buffers. This configuration - /// will be used to to restrict the number of concurrent chunk + /// will be used to restrict the number of concurrent chunk /// downloads at a time per `get()` request. /// /// This setting will also affect how much memory might be used @@ -1002,7 +1194,7 @@ pub struct EvictionPolicy { pub max_bytes: usize, /// When eviction starts based on hitting `max_bytes`, continue until - /// `max_bytes - evict_bytes` is met to create a low watermark. This stops + /// `max_bytes - evict_bytes` is met to create a low watermark. This stops /// operations from thrashing when the store is close to the limit. /// Default: 0 #[serde(default, deserialize_with = "convert_data_size_with_shellexpand")] @@ -1029,6 +1221,7 @@ pub enum ExperimentalCloudObjectSpec { Azure(ExperimentalAzureSpec), Ontap(ExperimentalOntapS3Spec), R2(ExperimentalR2Spec), + Oci(ExperimentalOciSpec), } impl Default for ExperimentalCloudObjectSpec { @@ -1094,7 +1287,9 @@ pub struct ExperimentalGcsSpec { #[serde(deny_unknown_fields)] #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] pub struct ExperimentalAzureSpec { - /// The Azure Storage account name. + /// The Azure Storage account name. Used to build the default container URL + /// `https://{account_name}.blob.core.windows.net/{container}` when `sas_url` + /// is not provided. #[serde(default, deserialize_with = "convert_string_with_shellexpand")] pub account_name: String, @@ -1102,19 +1297,24 @@ pub struct ExperimentalAzureSpec { #[serde(default, deserialize_with = "convert_string_with_shellexpand")] pub container: String, + /// Optional blob endpoint host override (for example an Azurite emulator host + /// such as `http://127.0.0.1:10000/devstoreaccount1`). When set, this replaces + /// the default `https://{account_name}.blob.core.windows.net` endpoint. The + /// container is always appended to form the final container URL. Ignored when + /// `sas_url` is set. + #[serde(default, deserialize_with = "convert_optional_string_with_shellexpand")] + pub endpoint: Option, + + /// Optional pre-formed SAS URL pointing at the container. When set, the store + /// uses it directly as the container URL with no credential (the SAS token is + /// expected to already be present in the URL), and `account_name`, `container`, + /// and `endpoint` are ignored for URL construction. + #[serde(default, deserialize_with = "convert_optional_string_with_shellexpand")] + pub sas_url: Option, + /// Common retry and upload configuration. #[serde(flatten)] pub common: CommonObjectSpec, - - /// Connection timeout in milliseconds. - /// Default: 3000 - #[serde(default, deserialize_with = "convert_duration_with_shellexpand")] - pub connection_timeout_s: u64, - - /// Read timeout in milliseconds. - /// Default: 3000 - #[serde(default, deserialize_with = "convert_duration_with_shellexpand")] - pub read_timeout_s: u64, } #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -1170,10 +1370,10 @@ pub struct CommonObjectSpec { #[serde(default, deserialize_with = "convert_boolean_with_shellexpand")] pub insecure_allow_http: bool, - /// Disable http/2 connections and only use http/1.1. Default client - /// configuration will have http/1.1 and http/2 enabled for connection - /// schemes. Http/2 should be disabled if environments have poor support - /// or performance related to http/2. Safe to keep default unless + /// Disable HTTP/2 connections and only use HTTP/1.1. Default client + /// configuration will have HTTP/1.1 and HTTP/2 enabled for connection + /// schemes. HTTP/2 should be disabled if environments have poor support + /// or performance related to HTTP/2. Safe to keep default unless /// underlying network environment, S3, or GCS API servers specify otherwise. /// /// Default: false @@ -1223,7 +1423,7 @@ pub struct ClientTlsConfig { #[serde(deny_unknown_fields)] #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] pub struct GrpcEndpoint { - /// The endpoint address (i.e. grpc(s)://example.com:443). + /// The endpoint address (i.e. `grpc(s)://example.com:443`). #[serde(deserialize_with = "convert_string_with_shellexpand")] pub address: String, /// The TLS configuration to use to connect to the endpoint (if grpcs). @@ -1263,7 +1463,7 @@ pub struct GrpcEndpoint { #[serde(deny_unknown_fields)] #[cfg_attr(feature = "dev-schema", derive(JsonSchema))] pub struct GrpcSpec { - /// Instance name for GRPC calls. Proxy calls will have the `instance_name` changed to this. + /// Instance name for gRPC calls. Proxy calls will have the `instance_name` changed to this. #[serde(default, deserialize_with = "convert_string_with_shellexpand")] pub instance_name: String, @@ -1277,19 +1477,20 @@ pub struct GrpcSpec { #[serde(default)] pub retry: Retry, - /// Limit the number of simultaneous upstream requests to this many. A - /// value of zero is treated as unlimited. If the limit is reached the + /// Limit the number of simultaneous upstream requests to this many. A + /// value of zero is treated as unlimited. If the limit is reached the /// request is queued. #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] pub max_concurrent_requests: usize, /// The number of connections to make to each specified endpoint to balance - /// the load over multiple TCP connections. Default 1. + /// the load over multiple TCP connections. + /// Default: 1. #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] pub connections_per_endpoint: usize, /// Maximum time (seconds) allowed for a single RPC request (e.g. a - /// ByteStream.Write call) before it is cancelled. + /// `ByteStream.Write` call) before it is cancelled. /// /// A value of 0 (the default) disables the per-RPC timeout. Dead /// connections are still detected by the HTTP/2 and TCP keepalive @@ -1335,6 +1536,130 @@ pub struct GrpcSpec { /// context (`traceparent` / `tracestate`) into every outgoing request. #[serde(default)] pub forward_headers: Vec, + + /// Optional and experimental: coalesce small-blob reads into + /// `BatchReadBlobs` RPCs instead of issuing one `ByteStream` `Read` + /// stream per blob. Each `ByteStream` read carries a fixed per-RPC cost, + /// so batching many small reads into a single `BatchReadBlobs` request + /// can dramatically reduce read latency for small blobs. + /// + /// Only full reads (offset 0, whole blob) of blobs at or below + /// `max_blob_size_bytes` are batched; everything else continues to use + /// the `ByteStream` `Read` path. + /// + /// Incompatible with `forward_headers`: batched reads share one upstream + /// RPC across many client requests, so per-client forwarded headers + /// (e.g. credentials) cannot be attached. Configuring both is rejected + /// at startup. + /// + /// Default: unset (disabled). When unset there is zero behavior change. + #[serde(default)] + pub experimental_read_batching: Option, + + /// Compress this store's own blob transfers on the wire with REAPI + /// `compressed-blobs/zstd`. Uploads and full-blob downloads of blobs at + /// or above 64 KiB are zstd-compressed; smaller blobs and ranged reads + /// keep the identity path. + /// + /// The upstream instance must have + /// `capabilities.remote_cache_compression` enabled, otherwise compressed + /// requests fail with `InvalidArgument`. This setting is what makes + /// NativeLink-to-NativeLink hops (for example worker to CAS) benefit + /// from wire compression; it is independent of what external clients + /// such as Bazel negotiate for themselves. + /// + /// Compressed uploads do not resume mid-stream (mirroring the REAPI + /// server contract): a transport failure part-way through a compressed + /// upload surfaces immediately to the caller instead of retrying, and + /// outer callers retry the whole upload. + /// + /// When combined with `experimental_chunked_uploads`, chunked uploads + /// take precedence for blobs at or above the chunking threshold. + /// + /// When zstd wire compression is enabled elsewhere in the process, + /// omitting this setting enables it automatically for CAS gRPC stores. + /// Set it explicitly to `false` to opt this store out. + /// + /// Default: inherited from the process-wide zstd wire-compression intent. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "convert_boolean_with_shellexpand" + )] + pub experimental_remote_cache_compression: Option, +} + +impl GrpcSpec { + /// Whether this store should use REAPI zstd wire compression. + #[must_use] + pub fn remote_cache_compression_enabled(&self) -> bool { + self.experimental_remote_cache_compression.unwrap_or(false) + } +} + +/// Configuration for experimental small-blob read coalescing in a gRPC +/// store. See [`GrpcSpec::experimental_read_batching`]. +#[derive(Serialize, Deserialize, Debug, Clone, Copy)] +#[serde(deny_unknown_fields)] +#[cfg_attr(feature = "dev-schema", derive(JsonSchema))] +pub struct GrpcReadBatchingConfig { + /// Only blobs at or below this size (in bytes) are eligible for + /// batching. Larger blobs always use the `ByteStream` `Read` path. + /// + /// Default: 131072 (128 KiB). + #[serde( + default = "default_read_batching_max_blob_size_bytes", + deserialize_with = "convert_data_size_with_shellexpand" + )] + pub max_blob_size_bytes: u64, + + /// Maximum total payload bytes packed into a single `BatchReadBlobs` + /// request. This should leave headroom under the 4 MiB default gRPC + /// message limit for protobuf framing overhead. + /// + /// Default: 3145728 (3 MiB). + #[serde( + default = "default_read_batching_max_batch_bytes", + deserialize_with = "convert_data_size_with_shellexpand" + )] + pub max_batch_bytes: u64, + + /// Maximum number of concurrent `BatchReadBlobs` RPCs dispatched by the + /// coalescer. Must be greater than zero. + /// + /// Default: 4. + #[serde( + default = "default_read_batching_dispatch_slots", + deserialize_with = "convert_numeric_with_shellexpand" + )] + pub dispatch_slots: usize, + + /// Bound on the number of payload bytes waiting in the coalescer queue. + /// When exceeded, new read requests bypass batching and fall back to the + /// regular `ByteStream` `Read` path instead of blocking. + /// + /// Default: 33554432 (32 MiB). + #[serde( + default = "default_read_batching_max_queued_bytes", + deserialize_with = "convert_data_size_with_shellexpand" + )] + pub max_queued_bytes: u64, +} + +const fn default_read_batching_max_blob_size_bytes() -> u64 { + 128 * 1024 // 128 KiB. +} + +const fn default_read_batching_max_batch_bytes() -> u64 { + 3 * 1024 * 1024 // 3 MiB. +} + +const fn default_read_batching_dispatch_slots() -> usize { + 4 +} + +const fn default_read_batching_max_queued_bytes() -> u64 { + 32 * 1024 * 1024 // 32 MiB. } /// The possible error codes that might occur on an upstream request. @@ -1454,18 +1779,42 @@ pub struct RedisSpec { #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] pub read_chunk_size: usize, - /// The number of connections to keep open to the redis server(s). + /// The number of connections to keep open to the redis servers. /// /// Default: 3 #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] pub connection_pool_size: usize, + /// Expire keys written by this store after this many seconds. + /// + /// Redis does not expire these on its own, so a store whose consumer + /// stops keeps every key it ever wrote. A BEP store is the case this + /// exists for: if the ETL stops consuming, the backlog grows until the + /// Redis node runs out of memory. + /// + /// Set this per store, not globally. The same store type backs the CAS + /// fast tier and the scheduler, and expiring scheduler state would drop + /// in-flight actions. + /// + /// This trades data for a bound. Anything not consumed within the window + /// is deleted, so the value has to exceed the longest consumer outage you + /// intend to survive, and it must also exceed how long a single upload can + /// take: the temp key an upload builds carries this same TTL, so a value + /// below the upload duration would expire the write in flight. + /// + /// Zero disables expiry. One second is the smallest value that enables it, + /// and any value that small is almost certainly a mistake. + /// + /// Default: 0 (keys never expire) + #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] + pub key_ttl_s: u64, + /// The maximum number of upload chunks to allow per update. /// This is used to limit the amount of memory used when uploading /// large objects to the redis server. A good rule of thumb is to /// think of the data as: /// `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` - /// (note: it is a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) + /// (note: it's a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) /// /// Default: 10 #[serde(default, deserialize_with = "convert_numeric_with_shellexpand")] @@ -1559,8 +1908,8 @@ pub struct Retry { #[serde(default)] pub jitter: f32, - /// A list of error codes to retry on, if this is not set then the default - /// error codes to retry on are used. These default codes are the most + /// A list of error codes to retry on, if this isn't set then the default + /// error codes to retry on are used. These default codes are the most /// likely to be non-permanent. /// - `Unknown` /// - `Cancelled` diff --git a/nativelink-config/tests/deserialization_test.rs b/nativelink-config/tests/deserialization_test.rs index 8d476ae24..c79ce3b43 100644 --- a/nativelink-config/tests/deserialization_test.rs +++ b/nativelink-config/tests/deserialization_test.rs @@ -382,6 +382,8 @@ mod optional_values_tests { } mod boolean_tests { + use nativelink_config::stores::GrpcSpec; + use crate::BoolEntity; #[test] @@ -404,6 +406,38 @@ mod boolean_tests { assert_eq!(deserialized.value, expected, "{input}"); } } + + #[test] + fn grpc_compression_accepts_string_and_environment_boolean() { + let string_spec: GrpcSpec = serde_json5::from_str( + r#"{ + endpoints: [{ address: "http://localhost:1234" }], + store_type: "cas", + experimental_remote_cache_compression: "true" + }"#, + ) + .expect("string boolean should deserialize"); + assert_eq!( + string_spec.experimental_remote_cache_compression, + Some(true) + ); + + // Safety: this test uses a unique variable and does not run code that + // reads mutable environment state concurrently. + unsafe { std::env::set_var("TEST_GRPC_REMOTE_CACHE_COMPRESSION", "false") }; + let environment_spec: GrpcSpec = serde_json5::from_str( + r#"{ + endpoints: [{ address: "http://localhost:1234" }], + store_type: "cas", + experimental_remote_cache_compression: "${TEST_GRPC_REMOTE_CACHE_COMPRESSION}" + }"#, + ) + .expect("environment boolean should deserialize"); + assert_eq!( + environment_spec.experimental_remote_cache_compression, + Some(false) + ); + } } mod shellexpand_tests { diff --git a/nativelink-error/BUILD.bazel b/nativelink-error/BUILD.bazel index e0d854b4c..59f4e1b25 100644 --- a/nativelink-error/BUILD.bazel +++ b/nativelink-error/BUILD.bazel @@ -16,6 +16,7 @@ rust_library( deps = [ "//nativelink-metric", "//nativelink-proto", + "@crates//:base64", "@crates//:mongodb", "@crates//:prost", "@crates//:prost-types", diff --git a/nativelink-error/Cargo.toml b/nativelink-error/Cargo.toml index 9c0cbde92..0d383e891 100644 --- a/nativelink-error/Cargo.toml +++ b/nativelink-error/Cargo.toml @@ -8,22 +8,23 @@ autoexamples = false autotests = true edition = "2024" name = "nativelink-error" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-metric = { path = "../nativelink-metric" } nativelink-proto = { path = "../nativelink-proto" } +base64 = { version = "0.22.1", default-features = false, features = ["std"] } mongodb = { version = "3", features = [ "compat-3-0-0", "rustls-tls", ], default-features = false } -prost = { version = "0.13.5", default-features = false } -prost-types = { version = "0.13.5", default-features = false, features = [ +prost = { version = "0.14.4", default-features = false } +prost-types = { version = "0.14.4", default-features = false, features = [ "std", ] } redis = { version = "1.0.0", default-features = false } -reqwest = { version = "0.12", default-features = false } +reqwest = { version = "0.13", default-features = false } rustls-pki-types = { version = "1.13.1", default-features = false } serde = { version = "1.0.219", default-features = false, features = ["derive"] } serde_json5 = { version = "0.2.1", default-features = false } @@ -33,7 +34,7 @@ tokio = { version = "1.52.2", features = [ "rt-multi-thread", "signal", ], default-features = false } -tonic = { version = "0.13.0", features = [ +tonic = { version = "0.14.0", features = [ "tls-ring", "transport", ], default-features = false } diff --git a/nativelink-error/src/lib.rs b/nativelink-error/src/lib.rs index 791e0bf26..3d2605e5e 100644 --- a/nativelink-error/src/lib.rs +++ b/nativelink-error/src/lib.rs @@ -329,21 +329,55 @@ impl From for Error { impl From for Error { fn from(error: redis::RedisError) -> Self { use redis::ErrorKind::{ - AuthenticationFailed, InvalidClientConfig, Io as IoError, Parse as ParseError, + AuthenticationFailed, ClusterConnectionNotFound, EmptySentinelList, + InvalidClientConfig, Io as IoError, MasterNameNotFoundBySentinel, + NoValidReplicasFoundBySentinel, Parse as ParseError, RESP3NotSupported, Server, UnexpectedReturnType, }; + use redis::ServerErrorKind::{ + BusyLoading, ClusterDown, MasterDown, NoPerm, ReadOnly, TryAgain, + }; // Conversions here are based on https://grpc.github.io/grpc/core/md_doc_statuscodes.html. + // + // The distinction that matters most is retryable vs not. These statuses + // reach REAPI clients directly, and Bazel treats INVALID_ARGUMENT as + // permanent: it fails the build instantly rather than retrying. So + // anything caused by the state of the Redis deployment — a failover in + // progress, a dropped connection, a node still loading its dataset — + // must NOT land there, or a routine blip becomes a failed CI run. let code = match error.kind() { - AuthenticationFailed => Code::PermissionDenied, - ParseError | UnexpectedReturnType | InvalidClientConfig => Code::InvalidArgument, + AuthenticationFailed | Server(NoPerm) => Code::PermissionDenied, + + // Topology in flux. Sentinel failover makes these normal and + // brief: the master moved and the client has not caught up yet. + // Surfacing MasterNameNotFoundBySentinel as INVALID_ARGUMENT is + // what turned a 1-2 minute sentinel failover into a dead build. + MasterNameNotFoundBySentinel + | NoValidReplicasFoundBySentinel + | ClusterConnectionNotFound + | Server(ClusterDown | MasterDown | TryAgain | BusyLoading | ReadOnly) => { + Code::Unavailable + } + + // A timeout is worth distinguishing from a dead connection, but + // both are transient and both are retryable. IoError => { if error.is_timeout() { Code::DeadlineExceeded } else { - Code::Internal + Code::Unavailable } } + + // Genuine misconfiguration by the operator — retrying cannot help. + InvalidClientConfig | EmptySentinelList | RESP3NotSupported => Code::InvalidArgument, + + // Server-side or protocol faults. Not the caller's argument, so + // not InvalidArgument: a malformed reply is our problem or the + // server's, and it is at least worth a retry. + ParseError | UnexpectedReturnType => Code::Internal, + _ => Code::Unknown, }; @@ -418,6 +452,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: base64::DecodeError) -> Self { + Self::from_std_err(Code::Internal, &err) + } +} + pub trait ResultExt { /// # Errors /// diff --git a/nativelink-error/tests/error_tests.rs b/nativelink-error/tests/error_tests.rs index 8458a27cd..688c24706 100644 --- a/nativelink-error/tests/error_tests.rs +++ b/nativelink-error/tests/error_tests.rs @@ -24,3 +24,101 @@ fn walkdir_source_error() { ); } } + +/// Redis failures reach REAPI clients as gRPC statuses, and `Bazel` treats +/// `INVALID_ARGUMENT` as permanent — no retry, build over. Anything caused by +/// the state of the `Redis` deployment rather than by the caller's request has +/// to map to a retryable status, or a routine failover fails CI. +mod redis_error_codes { + use nativelink_error::{Code, Error}; + use redis::{ErrorKind, RedisError, ServerErrorKind}; + + fn code_of(kind: ErrorKind) -> Code { + let err: Error = RedisError::from((kind, "synthetic")).into(); + err.code + } + + #[test] + fn sentinel_failover_is_retryable() { + // The exact shape observed killing a customer build mid-failover. + assert_eq!( + code_of(ErrorKind::MasterNameNotFoundBySentinel), + Code::Unavailable + ); + assert_eq!( + code_of(ErrorKind::NoValidReplicasFoundBySentinel), + Code::Unavailable + ); + } + + #[test] + fn transient_server_states_are_retryable() { + for kind in [ + ServerErrorKind::ClusterDown, + ServerErrorKind::MasterDown, + ServerErrorKind::TryAgain, + ServerErrorKind::BusyLoading, + ServerErrorKind::ReadOnly, + ] { + assert_eq!( + code_of(ErrorKind::Server(kind)), + Code::Unavailable, + "{kind:?} is transient and must be retryable" + ); + } + assert_eq!( + code_of(ErrorKind::ClusterConnectionNotFound), + Code::Unavailable + ); + } + + #[test] + fn dropped_connection_is_unavailable_and_timeout_is_deadline_exceeded() { + let dropped: Error = RedisError::from(std::io::Error::new( + std::io::ErrorKind::ConnectionReset, + "reset by peer", + )) + .into(); + assert_eq!(dropped.code, Code::Unavailable); + + let timed_out: Error = RedisError::from(std::io::Error::new( + std::io::ErrorKind::TimedOut, + "timed out", + )) + .into(); + assert_eq!(timed_out.code, Code::DeadlineExceeded); + } + + /// A malformed reply is a fault on our side or the server's, not a bad + /// argument from the client. This is the class that failed builds through + /// the `FT.AGGREGATE` expiry race. + #[test] + fn protocol_faults_are_internal_not_invalid_argument() { + assert_eq!(code_of(ErrorKind::Parse), Code::Internal); + assert_eq!(code_of(ErrorKind::UnexpectedReturnType), Code::Internal); + } + + /// Operator misconfiguration is the one case retrying genuinely cannot + /// help, so it stays non-retryable. + #[test] + fn misconfiguration_stays_invalid_argument() { + assert_eq!( + code_of(ErrorKind::InvalidClientConfig), + Code::InvalidArgument + ); + assert_eq!(code_of(ErrorKind::EmptySentinelList), Code::InvalidArgument); + assert_eq!(code_of(ErrorKind::RESP3NotSupported), Code::InvalidArgument); + } + + #[test] + fn auth_failures_are_permission_denied() { + assert_eq!( + code_of(ErrorKind::AuthenticationFailed), + Code::PermissionDenied + ); + assert_eq!( + code_of(ErrorKind::Server(ServerErrorKind::NoPerm)), + Code::PermissionDenied + ); + } +} diff --git a/nativelink-error/tests/lib_tests.rs b/nativelink-error/tests/lib_tests.rs index b1ee6200b..7c1eb42d6 100644 --- a/nativelink-error/tests/lib_tests.rs +++ b/nativelink-error/tests/lib_tests.rs @@ -58,11 +58,14 @@ fn test_redis_error_conversion_invalid_argument() { } #[test] -fn test_redis_error_conversion_internal() { - let redis_error: redis::RedisError = (RedisErrorKind::Io, "Internal error").into(); +fn test_redis_error_conversion_io_is_unavailable() { + // An I/O error means the connection to Redis broke, which is transient + // and retryable — clients must be told UNAVAILABLE so they retry rather + // than fail the operation outright. + let redis_error: redis::RedisError = (RedisErrorKind::Io, "Connection error").into(); let error: Error = redis_error.into(); - assert_eq!(error.code, Code::Internal); - assert!(error.messages[0].contains("Internal error")); + assert_eq!(error.code, Code::Unavailable); + assert!(error.messages[0].contains("Connection error")); } #[test] @@ -275,7 +278,7 @@ fn test_error_make_input_err_macro() { #[test] fn test_error_conversion_from_prost_decode_error() { - let prost_error = prost::DecodeError::new("Decode failure"); + let prost_error = prost::DecodeError::new_unexpected_type_url("Decode failure", "http://foo"); let error: Error = prost_error.into(); assert_eq!(error.code, Code::Internal); assert!( diff --git a/nativelink-macro/Cargo.toml b/nativelink-macro/Cargo.toml index 5b9bb8937..9a3fb777d 100644 --- a/nativelink-macro/Cargo.toml +++ b/nativelink-macro/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-macro" -version = "1.5.2" +version = "1.6.4" [lib] proc-macro = true @@ -12,4 +12,9 @@ proc-macro = true [dependencies] proc-macro2 = { version = "1.0.94", default-features = false } quote = { version = "1.0.40", default-features = false } -syn = { version = "2.0.117", default-features = false } +syn = { version = "3.0.0", default-features = false, features = [ + "full", + "parsing", + "printing", + "proc-macro", +] } diff --git a/nativelink-metric/Cargo.toml b/nativelink-metric/Cargo.toml index 15162b7da..7895fca77 100644 --- a/nativelink-metric/Cargo.toml +++ b/nativelink-metric/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-metric" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-metric-macro-derive = { path = "nativelink-metric-macro-derive" } diff --git a/nativelink-metric/nativelink-metric-macro-derive/Cargo.toml b/nativelink-metric/nativelink-metric-macro-derive/Cargo.toml index 37f45137e..1552166a3 100644 --- a/nativelink-metric/nativelink-metric-macro-derive/Cargo.toml +++ b/nativelink-metric/nativelink-metric-macro-derive/Cargo.toml @@ -1,7 +1,7 @@ [package] edition = "2024" name = "nativelink-metric-macro-derive" -version = "1.5.2" +version = "1.6.4" [lib] proc-macro = true @@ -9,4 +9,9 @@ proc-macro = true [dependencies] proc-macro2 = { version = "1.0.94", default-features = false } quote = { version = "1.0.40", default-features = false } -syn = { version = "2.0.117", default-features = false } +syn = { version = "3.0.0", default-features = false, features = [ + "derive", + "parsing", + "printing", + "proc-macro", +] } diff --git a/nativelink-metric/nativelink-metric-macro-derive/src/lib.rs b/nativelink-metric/nativelink-metric-macro-derive/src/lib.rs index 4488e4a87..b0e1aa969 100644 --- a/nativelink-metric/nativelink-metric-macro-derive/src/lib.rs +++ b/nativelink-metric/nativelink-metric-macro-derive/src/lib.rs @@ -93,7 +93,6 @@ impl ToTokens for MetricKind { } /// Holds general information about a specific field that is to be published. -#[derive(Debug)] struct MetricFieldMetaData<'a> { field_name: &'a Ident, metric_kind: MetricKind, @@ -133,7 +132,6 @@ impl<'a> MetricFieldMetaData<'a> { /// Holds the template information about the struct. This is needed /// to create the `MetricsComponent` impl. -#[derive(Debug)] struct Generics<'a> { implementation: ImplGenerics<'a>, ty: TypeGenerics<'a>, @@ -142,7 +140,6 @@ struct Generics<'a> { /// Holds metadata about the struct that is having `MetricsComponent` /// implemented. -#[derive(Debug)] struct MetricStruct<'a> { name: &'a Ident, metric_fields: Vec>, diff --git a/nativelink-proto/BUILD.bazel b/nativelink-proto/BUILD.bazel index e621d0227..32a5e3c8d 100644 --- a/nativelink-proto/BUILD.bazel +++ b/nativelink-proto/BUILD.bazel @@ -33,8 +33,7 @@ rust_binary( srcs = ["gen_protos_tool.rs"], deps = [ "@crates//:clap", - "@crates//:prost-build", - "@crates//:tonic-build", + "@crates//:tonic-prost-build", ], ) @@ -155,6 +154,7 @@ rust_library( "@crates//:prost", "@crates//:prost-types", "@crates//:tonic", + "@crates//:tonic-prost", ], ) diff --git a/nativelink-proto/Cargo.toml b/nativelink-proto/Cargo.toml index 595e93870..d7d27db23 100644 --- a/nativelink-proto/Cargo.toml +++ b/nativelink-proto/Cargo.toml @@ -2,7 +2,7 @@ [package] edition = "2024" name = "nativelink-proto" -version = "1.5.2" +version = "1.6.4" [lib] doctest = false # because some of the generated protos have things that look like doctests but break @@ -13,21 +13,19 @@ path = "genproto/lib.rs" derive_more = { version = "2.0.1", default-features = false, features = [ "debug", ] } -prost = { version = "0.13.5", default-features = false } -prost-types = { version = "0.13.5", default-features = false } -tonic = { version = "0.13.0", features = [ +prost = { version = "0.14.4", default-features = false } +prost-types = { version = "0.14.4", default-features = false } +tonic = { version = "0.14.0", features = [ "codegen", - "prost", "tls-ring", "transport", ], default-features = false } +tonic-prost = { version = "0.14.6", default-features = false } [dev-dependencies] -prost-build = { version = "0.13.5", default-features = false } -tonic-build = { version = "0.13.0", features = [ - "prost", +tonic-prost-build = { version = "0.14.0", features = [ ], default-features = false } [package.metadata.cargo-machete] # Used by gen_protos_tool.rs -ignored = ["prost-build", "tonic-build"] +ignored = ["tonic-prost-build"] diff --git a/nativelink-proto/build/bazel/remote/execution/v2/remote_execution.proto b/nativelink-proto/build/bazel/remote/execution/v2/remote_execution.proto index ebfcea3c7..b23d01ae0 100644 --- a/nativelink-proto/build/bazel/remote/execution/v2/remote_execution.proto +++ b/nativelink-proto/build/bazel/remote/execution/v2/remote_execution.proto @@ -429,6 +429,125 @@ service ContentAddressableStorage { rpc GetTree(GetTreeRequest) returns (stream GetTreeResponse) { option (google.api.http) = { get: "/v2/{instance_name=**}/blobs/{root_digest.hash}/{root_digest.size_bytes}:getTree" }; } + + // SplitBlob retrieves information about how a blob is split into chunks. + // + // This call returns information about how a blob is split into chunks, and + // returns a list of the chunk digests. Using the returned list of chunk digests, + // a client can check which chunks are locally available and only fetch the + // missing ones. The desired blob can be assembled by concatenating the fetched + // chunks in the order of the digests in the list. The chunks SHOULD all be + // available in the CAS. + // + // This API can be used to reduce the required data to download a large blob + // from CAS if some chunks from similar blobs are locally available. For this + // procedure to work properly, blobs SHOULD be split in a content-defined way, + // rather than with fixed-sized chunking. + // + // If a split request is answered successfully, a client can expect the + // following guarantees from the server: + // 1. The blob chunks are stored in CAS. + // 2. Concatenating the blob chunks in the order of the digest list returned + // by the server results in the original blob. + // + // Servers which implement this functionality MUST declare that they support + // it by setting the + // [CacheCapabilities.split_blob_support][build.bazel.remote.execution.v2.CacheCapabilities.split_blob_support] + // field accordingly. + // + // Clients MUST check that the server supports this capability, before using + // it. + // + // Clients SHOULD verify that the digest of the blob assembled by the fetched + // chunks is equal to the requested blob digest. + // + // The lifetimes of the generated chunk blobs MAY be independent of the + // lifetime of the original blob. In particular: + // * A blob and any chunk derived from it MAY be evicted from the CAS at + // different times. + // * A call to [SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + // extends the lifetime of the original blob, and sets the lifetimes of + // the resulting chunks (or extends the lifetimes of already-existing + // chunks). + // * Touching a chunk extends its lifetime, but the server MAY choose not + // to extend the lifetime of the original blob. + // * Touching the original blob extends its lifetime, but the server MAY + // choose not to extend the lifetimes of chunks derived from it. + // + // When blob splitting and splicing is used at the same time, the clients and + // the server SHOULD agree out-of-band upon a chunking algorithm used by both + // parties to benefit from each other's chunk data and avoid unnecessary data + // duplication. + // + // Errors: + // + // * `NOT_FOUND`: The requested blob is not present in the CAS, OR there is no + // split information available for the blob, OR at least one chunk needed to + // reconstruct the blob is missing from the CAS. + // * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob + // chunks. + rpc SplitBlob(SplitBlobRequest) returns (SplitBlobResponse) { + option (google.api.http) = { get: "/v2/{instance_name=**}/blobs/{blob_digest.hash}/{blob_digest.size_bytes}:splitBlob" }; + } + + // SpliceBlob tells the CAS how chunks can compose a blob. + // + // This is the complementary operation to the + // [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + // function to handle the chunked upload of large blobs to save upload + // traffic. + // + // When uploading a large blob using chunked upload, clients MUST first upload + // all chunks to the CAS, then call this RPC to tell the server how those chunks + // compose the original blob. The chunks referenced in the SpliceBlob call SHOULD be + // available in the CAS before calling this RPC. + // + // If a client needs to upload a large blob and is able to split a blob into + // chunks in such a way that reusable chunks are obtained, e.g., by means of + // content-defined chunking, it can first determine which parts of the blob + // are already available in the remote CAS and upload the missing chunks, and + // then use this API to store information on how the chunks compose the + // original blob. + // + // Servers which implement this functionality MUST declare that they support + // it by setting the + // [CacheCapabilities.splice_blob_support][build.bazel.remote.execution.v2.CacheCapabilities.splice_blob_support] + // field accordingly. + // + // Clients MUST check that the server supports this capability, before using + // it. + // + // In order to ensure data consistency of the CAS, the server MUST only add + // blobs to the CAS after verifying their digests. In particular, servers MUST NOT + // trust digests provided by the client. The server MAY accept a request as no-op + // if the client-specified blob is already in CAS or if information on how to + // construct the blob from chunks is available. If the client-specified blob is + // not already in the CAS, the server MUST verify that the digest of the newly + // created blob assembled from chunks matches the digest specified by the + // client, and reject the request if they differ. Servers MAY choose to allow + // overwriting existing chunk mappings or to store multiple chunk mappings for + // the same blob. + // + // When blob splitting and splicing is used at the same time, the clients and + // the server SHOULD agree out-of-band upon a chunking algorithm used by both + // parties to benefit from each other's chunk data and avoid unnecessary data + // duplication. + // + // Errors: + // + // * `NOT_FOUND`: At least one of the blob chunks is not present in the CAS. + // * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the + // spliced blob. + // * `INVALID_ARGUMENT`: The digest of the spliced blob is different from the + // provided expected digest. + // * `ALREADY_EXISTS`: The blob already exists in CAS and the server did not + // extend the lifetime of the chunks specified in the request, e.g. because + // it prefers a different chunking and extended those instead. Clients can + // call [SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + // to check what chunk mapping the server is using. + rpc SpliceBlob(SpliceBlobRequest) returns (SpliceBlobResponse) { + option (google.api.http) = { post: "/v2/{instance_name=**}/blobs:spliceBlob" body: "*" }; + } } // The Capabilities service may be used by remote execution clients to query @@ -1777,6 +1896,100 @@ message GetTreeResponse { string next_page_token = 2; } +// A request message for +// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]. +message SplitBlobRequest { + // The instance of the execution system to operate against. A server may + // support multiple instances of the execution system (with their own workers, + // storage, caches, etc.). The server MAY require use of this field to select + // between them in an implementation-defined fashion, otherwise it can be + // omitted. + string instance_name = 1; + + // The digest of the blob to be split. + Digest blob_digest = 2; + + // The digest function of the blob to be split. + // + // If the digest function used is one of MD5, MURMUR3, SHA1, SHA256, + // SHA384, SHA512, or VSO, the client MAY leave this field unset. In + // that case the server SHOULD infer the digest function using the + // length of the blob digest hashes and the digest functions announced + // in the server's capabilities. + DigestFunction.Value digest_function = 3; + + // The chunking function that the client prefers to use. + // + // The server MAY use a different chunking function. + ChunkingFunction.Value chunking_function = 4; +} + +// A response message for +// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]. +message SplitBlobResponse { + // The ordered list of digests of the chunks into which the blob was split. + // The original blob is assembled by concatenating the chunk data according to + // the order of the digests given by this list. + // + // The server MUST use the same digest function as the one explicitly or + // implicitly (through hash length) specified in the split request. + repeated Digest chunk_digests = 1; + + // The chunking function used to split the blob. + ChunkingFunction.Value chunking_function = 2; +} + +// A request message for +// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob]. +message SpliceBlobRequest { + // The instance of the execution system to operate against. A server may + // support multiple instances of the execution system (with their own workers, + // storage, caches, etc.). The server MAY require use of this field to select + // between them in an implementation-defined fashion, otherwise it can be + // omitted. + string instance_name = 1; + + // Expected digest of the spliced blob. The client MUST set this field due + // to the following reasons: + // 1. It allows the server to perform an early existence check of the blob + // or existing chunks that assemble the blob before spending the splicing + // effort, as described in the [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob] + // documentation. + // 2. It allows servers with different storage backends to dispatch the + // request to the correct storage backend based on the size and/or the + // hash of the blob. + // 3. If chunking information already exists for the blob, it allows + // the server to keep the existing chunking information or replace it with + // new chunking information. + Digest blob_digest = 2; + + // The ordered list of digests of the chunks which need to be concatenated to + // assemble the original blob. + repeated Digest chunk_digests = 3; + + // The digest function of all chunks to be concatenated and of the blob to be + // spliced. The server MUST use the same digest function for both cases. + // + // If the digest function used is one of MD5, MURMUR3, SHA1, SHA256, SHA384, + // SHA512, or VSO, the client MAY leave this field unset. In that case the + // server SHOULD infer the digest function using the length of the blob digest + // hashes and the digest functions announced in the server's capabilities. + DigestFunction.Value digest_function = 4; + + // The chunking function that the client used to split the blob. + ChunkingFunction.Value chunking_function = 5; +} + +// A response message for +// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob]. +message SpliceBlobResponse { + // Computed digest of the spliced blob. + // + // The server MUST use the same digest function as the one explicitly or + // implicitly (through hash length) specified in the splice request. + Digest blob_digest = 1; +} + // A request message for // [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities]. message GetCapabilitiesRequest { @@ -1967,6 +2180,34 @@ message Compressor { } } +// The chunking function is used to split a blob into chunks. +// +// The server advertises support for a chunking function by setting the +// corresponding params field in +// [CacheCapabilities][build.bazel.remote.execution.v2.CacheCapabilities]. +// For example, if fast_cdc_2020_params is set, the server supports FAST_CDC_2020. +// +// For optimal deduplication, clients SHOULD use an advertised chunking function. +// When clients use UNKNOWN, the server chooses an algorithm for SplitBlob and +// simply verifies chunk concatenation for SpliceBlob. +message ChunkingFunction { + enum Value { + // No specific algorithm. Servers MUST always accept this value. + // For SplitBlob, the server chooses the algorithm. For SpliceBlob, the + // server only verifies that chunks concatenate to form the expected blob. + UNKNOWN = 0; + + // The FastCDC chunking algorithm as described in the 2020 paper by + // Wen Xia, et al. See https://ieeexplore.ieee.org/document/9055082 + // for details. + FAST_CDC_2020 = 1; + + // The RepMaxCDC chunking algorithm as implemented by buildbarn/go-cdc. + // See https://github.com/buildbarn/go-cdc for details. + REP_MAX_CDC = 2; + } +} + // Capabilities of the remote cache system. message CacheCapabilities { // All the digest functions supported by the remote cache. @@ -2000,6 +2241,121 @@ message CacheCapabilities { // [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs] // requests. repeated Compressor.Value supported_batch_update_compressors = 7; + + // The maximum blob size that the server will accept for CAS blob uploads. + // - If it is 0, it means there is no limit set. A client may assume + // arbitrarily large blobs may be uploaded to and downloaded from the cache. + // - If it is larger than 0, implementations SHOULD NOT attempt to upload + // blobs with size larger than the limit. Servers SHOULD reject blob + // uploads over the `max_cas_blob_size_bytes` limit with response code + // `INVALID_ARGUMENT` + // - If the cache implementation returns a given limit, it MAY still serve + // blobs larger than this limit. + int64 max_cas_blob_size_bytes = 8; + + // Whether blob splitting is supported for the particular server/instance. If + // yes, the server/instance implements the specified behavior for blob + // splitting and a meaningful result can be expected from the + // [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + // operation. + bool split_blob_support = 9; + + // Whether blob splicing is supported for the particular server/instance. If + // yes, the server/instance implements the specified behavior for blob + // splicing and a meaningful result can be expected from the + // [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob] + // operation. + bool splice_blob_support = 10; + + // The parameters for the FastCDC 2020 chunking algorithm. + // If set, the server supports the FastCDC chunking algorithm. + FastCdc2020Params fast_cdc_2020_params = 11; + + // The parameters for the RepMaxCDC chunking algorithm. + // If set, the server supports the RepMaxCDC chunking algorithm. + RepMaxCdcParams rep_max_cdc_params = 12; +} + +// Parameters for the FastCDC content-defined chunking algorithm. +// +// Implementations MUST follow the FastCDC 2020 paper by Wen Xia, et al.: +// https://ieeexplore.ieee.org/document/9055082 +// +// Supported implementations: +// - Rust: https://docs.rs/fastcdc/3.2.1/fastcdc/v2020/index.html +// - Go: https://github.com/buildbuddy-io/fastcdc2020 +// +// Test vectors can be found in the accompanying fastcdc2020_test_vectors.txt file. +// +// Implementations MUST use normalization level 2, which has been found +// successful for build artifacts with an average chunk size of 512 KiB. +// +// Key algorithm components from the paper: +// +// GEAR table: 256 64-bit integers for the rolling hash, computed as: +// GEAR[i] = high_64_bits(MD5(byte(i))) for i in 0..255 +// +// MASKS table: Bit patterns for chunk boundary detection, derived from +// the C reference implementation. The mask selection based on average +// chunk size SHOULD match the paper. +// +// The minimum and maximum chunk sizes MUST be derived from the average: +// - min_chunk_size = avg_chunk_size_bytes / 4 +// - max_chunk_size = avg_chunk_size_bytes * 4 +// +// Blobs smaller than max_chunk_size (avg_chunk_size_bytes * 4) SHOULD be +// uploaded without chunking. +// +// If any of the advertised parameters are not within the expected range, +// the client SHOULD ignore FastCDC chunking function support. +message FastCdc2020Params { + // The average (expected) chunk size for the FastCDC chunking algorithm. + // The value MUST be between 1 KiB and 1 MiB. The recommended value is + // 524288 (512 KiB). + uint64 avg_chunk_size_bytes = 1; + + // The seed for the FastCDC mask generation. + // The recommended value is 0. + // + // All clients sharing a cache SHOULD use the same seed to maximize + // chunk reuse. + uint32 seed = 2; +} + +// Parameters for the RepMaxCDC content-defined chunking algorithm. +// +// Supported implementations: +// - Go: https://github.com/buildbarn/go-cdc +// +// Key algorithm components: +// +// GEAR table: 256 64-bit integers for the rolling hash, computed as: +// GEAR[i] = high_64_bits(MD5(byte(i))) for i in 0..255 +// +// The algorithm repeatedly applies chunking until all chunks are in the +// range [min_chunk_size_bytes, 2*min_chunk_size_bytes). Cutting points are +// selected where the Gear rolling hash is maximized within a lookahead +// window of horizon_size_bytes. +// +// For sufficiently large files, the average chunk size prior to +// deduplication will approximately be min_chunk_size_bytes divided by +// Rényi's parking constant (0.7475979203...). More details: +// https://mathworld.wolfram.com/RenyisParkingConstants.html +// +// If any of the advertised parameters are not within the expected range, +// the client SHOULD ignore RepMaxCDC chunking function support. +message RepMaxCdcParams { + // The minimum chunk size for the RepMaxCDC chunking algorithm. + // The value MUST be at least 64 bytes (the Gear hash window size). + // All chunks will be in the range [min_chunk_size_bytes, 2*min_chunk_size_bytes). + // The recommended value is 262144 (256 KiB). + uint64 min_chunk_size_bytes = 1; + + // The lookahead window for finding optimal cutting points. + // Larger values improve deduplication quality with diminishing returns. + // Setting to 0 produces uniform chunks of min_chunk_size_bytes. + // The recommended value is 8 * min_chunk_size_bytes. + uint64 horizon_size_bytes = 2; } // Capabilities of the remote execution system. diff --git a/nativelink-proto/com/github/trace_machina/nativelink/remote_execution/worker_api.proto b/nativelink-proto/com/github/trace_machina/nativelink/remote_execution/worker_api.proto index 3c5e25982..055074c79 100644 --- a/nativelink-proto/com/github/trace_machina/nativelink/remote_execution/worker_api.proto +++ b/nativelink-proto/com/github/trace_machina/nativelink/remote_execution/worker_api.proto @@ -125,7 +125,12 @@ message ActionResourceUsage { /// The worker ID that observed the resource usage. string worker_id = 4; - reserved 5; // NextId. + /// Total CPU time consumed by the action process tree, in milliseconds. + /// User and system time combined, summed across every process in the + /// action's process group. + uint64 cpu_time_ms = 5; + + reserved 6; // NextId. } /// Result sent back from the server when a node connects. diff --git a/nativelink-proto/gen_protos_tool.rs b/nativelink-proto/gen_protos_tool.rs index 2374981e5..1a4520b3a 100644 --- a/nativelink-proto/gen_protos_tool.rs +++ b/nativelink-proto/gen_protos_tool.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::path::PathBuf; use clap::{Arg, ArgAction, Command}; -use prost_build::Config; +use tonic_prost_build::Config; fn main() -> std::io::Result<()> { let matches = Command::new("Rust gRPC Codegen") @@ -48,8 +48,8 @@ fn main() -> std::io::Result<()> { config.skip_debug(structs_with_data_to_ignore.keys()); - tonic_build::configure() + tonic_prost_build::configure() .out_dir(output_dir) - .compile_protos_with_config(config, &paths, &["nativelink-proto"])?; + .compile_with_config(config, &paths, &[&"nativelink-proto".into()])?; Ok(()) } diff --git a/nativelink-proto/genproto/blaze.invocation_policy.pb.rs b/nativelink-proto/genproto/blaze.invocation_policy.pb.rs index a10ac2e5c..aed41e8b4 100644 --- a/nativelink-proto/genproto/blaze.invocation_policy.pb.rs +++ b/nativelink-proto/genproto/blaze.invocation_policy.pb.rs @@ -27,7 +27,7 @@ pub struct InvocationPolicy { pub strategy_policy: ::core::option::Option, } /// A policy for controlling the value of a flag. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct FlagPolicy { /// The name of the flag to enforce this policy on. /// @@ -55,7 +55,7 @@ pub struct FlagPolicy { } /// Nested message and enum types in `FlagPolicy`. pub mod flag_policy { - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum Operation { #[prost(message, tag = "3")] SetValue(super::SetValue), @@ -67,7 +67,7 @@ pub mod flag_policy { AllowValues(super::AllowValues), } } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct SetValue { /// Use this value for the specified flag, overriding any default or user-set /// value (unless behavior = APPEND for repeatable flags). @@ -179,9 +179,9 @@ pub mod set_value { /// policy wins, later policies on this same flag will still remove the /// expanded UseDefault, so there is a way around, but it's really best not to /// use this on expansion flags at all. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct UseDefault {} -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DisallowValues { /// It is an error for the user to use any of these values (that is, the Bazel /// command will fail), unless new_value or use_default is set. @@ -201,7 +201,7 @@ pub struct DisallowValues { } /// Nested message and enum types in `DisallowValues`. pub mod disallow_values { - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum ReplacementValue { /// If set and if the value of the flag is disallowed (including the default /// value of the flag if the user doesn't specify a value), use this value as @@ -221,7 +221,7 @@ pub mod disallow_values { UseDefault(super::UseDefault), } } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct AllowValues { /// It is an error for the user to use any value not in this list, unless /// new_value or use_default is set. @@ -232,7 +232,7 @@ pub struct AllowValues { } /// Nested message and enum types in `AllowValues`. pub mod allow_values { - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum ReplacementValue { /// If set and if the value of the flag is disallowed (including the default /// value of the flag if the user doesn't specify a value), use this value as diff --git a/nativelink-proto/genproto/blaze.pb.rs b/nativelink-proto/genproto/blaze.pb.rs index 109f397f8..711148724 100644 --- a/nativelink-proto/genproto/blaze.pb.rs +++ b/nativelink-proto/genproto/blaze.pb.rs @@ -42,7 +42,7 @@ pub struct ActionCacheStatistics { /// Nested message and enum types in `ActionCacheStatistics`. pub mod action_cache_statistics { /// Detailed information for a particular miss reason. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct MissDetail { #[prost(enumeration = "MissReason", tag = "1")] pub reason: i32, diff --git a/nativelink-proto/genproto/blaze.strategy_policy.pb.rs b/nativelink-proto/genproto/blaze.strategy_policy.pb.rs index f089b9349..a75c8db0c 100644 --- a/nativelink-proto/genproto/blaze.strategy_policy.pb.rs +++ b/nativelink-proto/genproto/blaze.strategy_policy.pb.rs @@ -56,7 +56,7 @@ pub struct MnemonicPolicy { pub strategy_allowlist: ::prost::alloc::vec::Vec, } /// Per-mnemonic allowlist settings. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StrategiesForMnemonic { #[prost(string, optional, tag = "1")] pub mnemonic: ::core::option::Option<::prost::alloc::string::String>, diff --git a/nativelink-proto/genproto/build.bazel.remote.asset.v1.pb.rs b/nativelink-proto/genproto/build.bazel.remote.asset.v1.pb.rs index c2a863a12..631dda38d 100644 --- a/nativelink-proto/genproto/build.bazel.remote.asset.v1.pb.rs +++ b/nativelink-proto/genproto/build.bazel.remote.asset.v1.pb.rs @@ -27,7 +27,7 @@ /// qualifier is recommended for this purpose. /// /// Qualifiers may be supplied in any order. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Qualifier { /// The "name" of the qualifier, for example "resource_type". /// No separation is made between 'standard' and 'nonstandard' @@ -311,7 +311,7 @@ pub struct PushBlobRequest { } /// A response message for /// [Push.PushBlob][build.bazel.remote.asset.v1.Push.PushBlob]. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct PushBlobResponse {} /// A request message for /// [Push.PushDirectory][build.bazel.remote.asset.v1.Push.PushDirectory]. @@ -369,7 +369,7 @@ pub struct PushDirectoryRequest { } /// A response message for /// [Push.PushDirectory][build.bazel.remote.asset.v1.Push.PushDirectory]. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct PushDirectoryResponse {} /// Generated client implementations. pub mod fetch_client { @@ -531,7 +531,7 @@ pub mod fetch_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/build.bazel.remote.asset.v1.Fetch/FetchBlob", ); @@ -557,7 +557,7 @@ pub mod fetch_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/build.bazel.remote.asset.v1.Fetch/FetchDirectory", ); @@ -573,179 +573,6 @@ pub mod fetch_client { } } } -/// Generated client implementations. -pub mod push_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// The Push service is complementary to the Fetch, and allows for - /// associating contents of URLs to be returned in future Fetch API calls. - /// - /// As with other services in the Remote Execution API, any call may return an - /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing - /// information about when the client should retry the request; clients SHOULD - /// respect the information provided. - #[derive(Debug, Clone)] - pub struct PushClient { - inner: tonic::client::Grpc, - } - impl PushClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> PushClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, - { - PushClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// These APIs associate the identifying information of a resource, as - /// indicated by URI and optionally Qualifiers, with content available in the - /// CAS. For example, associating a repository url and a commit id with a - /// Directory Digest. - /// - /// Servers *SHOULD* only allow trusted clients to associate content, and *MAY* - /// only allow certain URIs to be pushed. - /// - /// Clients *MUST* ensure associated content is available in CAS prior to - /// pushing. - /// - /// Clients *MUST* ensure the Qualifiers listed correctly match the contents, - /// and Servers *MAY* trust these values without validation. - /// Fetch servers *MAY* require exact match of all qualifiers when returning - /// content previously pushed, or allow fetching content with only a subset of - /// the qualifiers specified on Push. - /// - /// Clients can specify expiration information that the server *SHOULD* - /// respect. Subsequent requests can be used to alter the expiration time. - /// - /// A minimal compliant Fetch implementation may support only Push'd content - /// and return `NOT_FOUND` for any resource that was not pushed first. - /// Alternatively, a compliant implementation may choose to not support Push - /// and only return resources that can be Fetch'd from origin. - /// - /// Errors will be returned as gRPC Status errors. - /// The possible RPC errors include: - /// * `INVALID_ARGUMENT`: One or more arguments to the RPC were invalid. - /// * `RESOURCE_EXHAUSTED`: There is insufficient quota of some resource to - /// perform the requested operation. The client may retry after a delay. - /// * `UNAVAILABLE`: Due to a transient condition the operation could not be - /// completed. The client should retry. - /// * `INTERNAL`: An internal error occurred while performing the operation. - /// The client should retry. - pub async fn push_blob( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.asset.v1.Push/PushBlob", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("build.bazel.remote.asset.v1.Push", "PushBlob")); - self.inner.unary(req, path, codec).await - } - pub async fn push_directory( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.asset.v1.Push/PushDirectory", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new("build.bazel.remote.asset.v1.Push", "PushDirectory"), - ); - self.inner.unary(req, path, codec).await - } - } -} /// Generated server implementations. pub mod fetch_server { #![allow( @@ -943,7 +770,7 @@ pub mod fetch_server { let inner = self.inner.clone(); let fut = async move { let method = FetchBlobSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -988,7 +815,7 @@ pub mod fetch_server { let inner = self.inner.clone(); let fut = async move { let method = FetchDirectorySvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -1043,6 +870,179 @@ pub mod fetch_server { const NAME: &'static str = SERVICE_NAME; } } +/// Generated client implementations. +pub mod push_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// The Push service is complementary to the Fetch, and allows for + /// associating contents of URLs to be returned in future Fetch API calls. + /// + /// As with other services in the Remote Execution API, any call may return an + /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing + /// information about when the client should retry the request; clients SHOULD + /// respect the information provided. + #[derive(Debug, Clone)] + pub struct PushClient { + inner: tonic::client::Grpc, + } + impl PushClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> PushClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + PushClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// These APIs associate the identifying information of a resource, as + /// indicated by URI and optionally Qualifiers, with content available in the + /// CAS. For example, associating a repository url and a commit id with a + /// Directory Digest. + /// + /// Servers *SHOULD* only allow trusted clients to associate content, and *MAY* + /// only allow certain URIs to be pushed. + /// + /// Clients *MUST* ensure associated content is available in CAS prior to + /// pushing. + /// + /// Clients *MUST* ensure the Qualifiers listed correctly match the contents, + /// and Servers *MAY* trust these values without validation. + /// Fetch servers *MAY* require exact match of all qualifiers when returning + /// content previously pushed, or allow fetching content with only a subset of + /// the qualifiers specified on Push. + /// + /// Clients can specify expiration information that the server *SHOULD* + /// respect. Subsequent requests can be used to alter the expiration time. + /// + /// A minimal compliant Fetch implementation may support only Push'd content + /// and return `NOT_FOUND` for any resource that was not pushed first. + /// Alternatively, a compliant implementation may choose to not support Push + /// and only return resources that can be Fetch'd from origin. + /// + /// Errors will be returned as gRPC Status errors. + /// The possible RPC errors include: + /// * `INVALID_ARGUMENT`: One or more arguments to the RPC were invalid. + /// * `RESOURCE_EXHAUSTED`: There is insufficient quota of some resource to + /// perform the requested operation. The client may retry after a delay. + /// * `UNAVAILABLE`: Due to a transient condition the operation could not be + /// completed. The client should retry. + /// * `INTERNAL`: An internal error occurred while performing the operation. + /// The client should retry. + pub async fn push_blob( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.asset.v1.Push/PushBlob", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("build.bazel.remote.asset.v1.Push", "PushBlob")); + self.inner.unary(req, path, codec).await + } + pub async fn push_directory( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.asset.v1.Push/PushDirectory", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("build.bazel.remote.asset.v1.Push", "PushDirectory"), + ); + self.inner.unary(req, path, codec).await + } + } +} /// Generated server implementations. pub mod push_server { #![allow( @@ -1216,7 +1216,7 @@ pub mod push_server { let inner = self.inner.clone(); let fut = async move { let method = PushBlobSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -1261,7 +1261,7 @@ pub mod push_server { let inner = self.inner.clone(); let fut = async move { let method = PushDirectorySvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, diff --git a/nativelink-proto/genproto/build.bazel.remote.execution.v2.pb.rs b/nativelink-proto/genproto/build.bazel.remote.execution.v2.pb.rs index 3ac4f4a25..f4b7c43e7 100644 --- a/nativelink-proto/genproto/build.bazel.remote.execution.v2.pb.rs +++ b/nativelink-proto/genproto/build.bazel.remote.execution.v2.pb.rs @@ -260,7 +260,7 @@ pub struct Command { pub mod command { /// An `EnvironmentVariable` is one variable to set in the running program's /// environment. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct EnvironmentVariable { /// The variable name. #[prost(string, tag = "1")] @@ -308,7 +308,7 @@ pub mod platform { /// is implicitly part of the action digest, so even tiny changes in the names /// or values (like changing case) may result in different action cache /// entries. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Property { /// The property name. #[prost(string, tag = "1")] @@ -413,7 +413,7 @@ pub struct Directory { /// [SymlinkNodes][build.bazel.remote.execution.v2.SymlinkNode]. The server is /// responsible for specifying the property `name`s that it accepts. If /// permitted by the server, the same `name` may occur multiple times. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct NodeProperty { /// The property name. #[prost(string, tag = "1")] @@ -458,7 +458,7 @@ pub struct FileNode { /// A `DirectoryNode` represents a child of a /// [Directory][build.bazel.remote.execution.v2.Directory] which is itself /// a `Directory` and its associated metadata. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DirectoryNode { /// The name of the directory. #[prost(string, tag = "1")] @@ -521,7 +521,7 @@ pub struct SymlinkNode { /// Most protocol buffer implementations will always follow these rules when /// serializing, but care should be taken to avoid shortcuts. For instance, /// concatenating two messages to merge them may produce duplicate fields. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Digest { /// The hash. In the case of SHA-256, it will always be a lowercase hex string /// exactly 64 characters long. @@ -823,7 +823,7 @@ pub struct Tree { } /// An `OutputDirectory` is the output in an `ActionResult` corresponding to a /// directory's full contents rather than a single file. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct OutputDirectory { /// The full path of the directory relative to the working directory. The path /// separator is a forward slash `/`. Since this is a relative path, it MUST @@ -897,7 +897,7 @@ pub struct OutputSymlink { pub node_properties: ::core::option::Option, } /// An `ExecutionPolicy` can be used to control the scheduling of the action. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExecutionPolicy { /// The priority (relative importance) of this action. Generally, a lower value /// means that the action should be run sooner than actions having a greater @@ -913,7 +913,7 @@ pub struct ExecutionPolicy { } /// A `ResultsCachePolicy` is used for fine-grained control over how action /// outputs are stored in the CAS and Action Cache. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ResultsCachePolicy { /// The priority (relative importance) of this content in the overall cache. /// Generally, a lower value means a longer retention time or other advantage, @@ -928,7 +928,7 @@ pub struct ResultsCachePolicy { } /// A request message for /// [Execution.Execute][build.bazel.remote.execution.v2.Execution.Execute]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExecuteRequest { /// The instance of the execution system to operate against. A server may /// support multiple instances of the execution system (with their own workers, @@ -976,7 +976,7 @@ pub struct ExecuteRequest { pub digest_function: i32, } /// A `LogFile` is a log stored in the CAS. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct LogFile { /// The digest of the log contents. #[prost(message, optional, tag = "1")] @@ -1045,7 +1045,7 @@ pub struct ExecuteResponse { /// has reached the COMPLETED stage, it MUST set the [done /// field][google.longrunning.Operation.done] of the /// [Operation][google.longrunning.Operation] and terminate the stream. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExecutionStage {} /// Nested message and enum types in `ExecutionStage`. pub mod execution_stage { @@ -1131,7 +1131,7 @@ pub struct ExecuteOperationMetadata { } /// A request message for /// [WaitExecution][build.bazel.remote.execution.v2.Execution.WaitExecution]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct WaitExecutionRequest { /// The name of the [Operation][google.longrunning.Operation] /// returned by [Execute][build.bazel.remote.execution.v2.Execution.Execute]. @@ -1140,7 +1140,7 @@ pub struct WaitExecutionRequest { } /// A request message for /// [ActionCache.GetActionResult][build.bazel.remote.execution.v2.ActionCache.GetActionResult]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetActionResultRequest { /// The instance of the execution system to operate against. A server may /// support multiple instances of the execution system (with their own workers, @@ -1275,7 +1275,7 @@ pub struct BatchUpdateBlobsRequest { /// Nested message and enum types in `BatchUpdateBlobsRequest`. pub mod batch_update_blobs_request { /// A request corresponding to a single blob that the client wants to upload. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Request { /// The digest of the blob. This MUST be the digest of `data`. All /// digests MUST use the same digest function. @@ -1385,7 +1385,7 @@ pub mod batch_read_blobs_response { } /// A request message for /// [ContentAddressableStorage.GetTree][build.bazel.remote.execution.v2.ContentAddressableStorage.GetTree]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetTreeRequest { /// The instance of the execution system to operate against. A server may /// support multiple instances of the execution system (with their own workers, @@ -1438,8 +1438,106 @@ pub struct GetTreeResponse { pub next_page_token: ::prost::alloc::string::String, } /// A request message for -/// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities]. +/// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct SplitBlobRequest { + /// The instance of the execution system to operate against. A server may + /// support multiple instances of the execution system (with their own workers, + /// storage, caches, etc.). The server MAY require use of this field to select + /// between them in an implementation-defined fashion, otherwise it can be + /// omitted. + #[prost(string, tag = "1")] + pub instance_name: ::prost::alloc::string::String, + /// The digest of the blob to be split. + #[prost(message, optional, tag = "2")] + pub blob_digest: ::core::option::Option, + /// The digest function of the blob to be split. + /// + /// If the digest function used is one of MD5, MURMUR3, SHA1, SHA256, + /// SHA384, SHA512, or VSO, the client MAY leave this field unset. In + /// that case the server SHOULD infer the digest function using the + /// length of the blob digest hashes and the digest functions announced + /// in the server's capabilities. + #[prost(enumeration = "digest_function::Value", tag = "3")] + pub digest_function: i32, + /// The chunking function that the client prefers to use. + /// + /// The server MAY use a different chunking function. + #[prost(enumeration = "chunking_function::Value", tag = "4")] + pub chunking_function: i32, +} +/// A response message for +/// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob]. #[derive(Clone, PartialEq, ::prost::Message)] +pub struct SplitBlobResponse { + /// The ordered list of digests of the chunks into which the blob was split. + /// The original blob is assembled by concatenating the chunk data according to + /// the order of the digests given by this list. + /// + /// The server MUST use the same digest function as the one explicitly or + /// implicitly (through hash length) specified in the split request. + #[prost(message, repeated, tag = "1")] + pub chunk_digests: ::prost::alloc::vec::Vec, + /// The chunking function used to split the blob. + #[prost(enumeration = "chunking_function::Value", tag = "2")] + pub chunking_function: i32, +} +/// A request message for +/// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob]. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SpliceBlobRequest { + /// The instance of the execution system to operate against. A server may + /// support multiple instances of the execution system (with their own workers, + /// storage, caches, etc.). The server MAY require use of this field to select + /// between them in an implementation-defined fashion, otherwise it can be + /// omitted. + #[prost(string, tag = "1")] + pub instance_name: ::prost::alloc::string::String, + /// Expected digest of the spliced blob. The client MUST set this field due + /// to the following reasons: + /// 1. It allows the server to perform an early existence check of the blob + /// or existing chunks that assemble the blob before spending the splicing + /// effort, as described in the [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob] + /// documentation. + /// 2. It allows servers with different storage backends to dispatch the + /// request to the correct storage backend based on the size and/or the + /// hash of the blob. + /// 3. If chunking information already exists for the blob, it allows + /// the server to keep the existing chunking information or replace it with + /// new chunking information. + #[prost(message, optional, tag = "2")] + pub blob_digest: ::core::option::Option, + /// The ordered list of digests of the chunks which need to be concatenated to + /// assemble the original blob. + #[prost(message, repeated, tag = "3")] + pub chunk_digests: ::prost::alloc::vec::Vec, + /// The digest function of all chunks to be concatenated and of the blob to be + /// spliced. The server MUST use the same digest function for both cases. + /// + /// If the digest function used is one of MD5, MURMUR3, SHA1, SHA256, SHA384, + /// SHA512, or VSO, the client MAY leave this field unset. In that case the + /// server SHOULD infer the digest function using the length of the blob digest + /// hashes and the digest functions announced in the server's capabilities. + #[prost(enumeration = "digest_function::Value", tag = "4")] + pub digest_function: i32, + /// The chunking function that the client used to split the blob. + #[prost(enumeration = "chunking_function::Value", tag = "5")] + pub chunking_function: i32, +} +/// A response message for +/// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob]. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct SpliceBlobResponse { + /// Computed digest of the spliced blob. + /// + /// The server MUST use the same digest function as the one explicitly or + /// implicitly (through hash length) specified in the splice request. + #[prost(message, optional, tag = "1")] + pub blob_digest: ::core::option::Option, +} +/// A request message for +/// [Capabilities.GetCapabilities][build.bazel.remote.execution.v2.Capabilities.GetCapabilities]. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetCapabilitiesRequest { /// The instance of the execution system to operate against. A server may /// support multiple instances of the execution system (with their own workers, @@ -1473,7 +1571,7 @@ pub struct ServerCapabilities { } /// The digest function used for converting values into keys for CAS and Action /// Cache. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DigestFunction {} /// Nested message and enum types in `DigestFunction`. pub mod digest_function { @@ -1610,7 +1708,7 @@ pub mod digest_function { } } /// Describes the server/instance capabilities for updating the action cache. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionCacheUpdateCapabilities { #[prost(bool, tag = "1")] pub update_enabled: bool, @@ -1627,7 +1725,7 @@ pub struct PriorityCapabilities { /// Nested message and enum types in `PriorityCapabilities`. pub mod priority_capabilities { /// Supported range of priorities, including boundaries. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct PriorityRange { /// The minimum numeric value for this priority range, which represents the /// most urgent task or longest retained item. @@ -1640,7 +1738,7 @@ pub mod priority_capabilities { } } /// Describes how the server treats absolute symlink targets. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct SymlinkAbsolutePathStrategy {} /// Nested message and enum types in `SymlinkAbsolutePathStrategy`. pub mod symlink_absolute_path_strategy { @@ -1692,7 +1790,7 @@ pub mod symlink_absolute_path_strategy { } } /// Compression formats which may be supported. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Compressor {} /// Nested message and enum types in `Compressor`. pub mod compressor { @@ -1749,6 +1847,68 @@ pub mod compressor { } } } +/// The chunking function is used to split a blob into chunks. +/// +/// The server advertises support for a chunking function by setting the +/// corresponding params field in +/// [CacheCapabilities][build.bazel.remote.execution.v2.CacheCapabilities]. +/// For example, if fast_cdc_2020_params is set, the server supports FAST_CDC_2020. +/// +/// For optimal deduplication, clients SHOULD use an advertised chunking function. +/// When clients use UNKNOWN, the server chooses an algorithm for SplitBlob and +/// simply verifies chunk concatenation for SpliceBlob. +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ChunkingFunction {} +/// Nested message and enum types in `ChunkingFunction`. +pub mod chunking_function { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum Value { + /// No specific algorithm. Servers MUST always accept this value. + /// For SplitBlob, the server chooses the algorithm. For SpliceBlob, the + /// server only verifies that chunks concatenate to form the expected blob. + Unknown = 0, + /// The FastCDC chunking algorithm as described in the 2020 paper by + /// Wen Xia, et al. See + /// for details. + FastCdc2020 = 1, + /// The RepMaxCDC chunking algorithm as implemented by buildbarn/go-cdc. + /// See for details. + RepMaxCdc = 2, + } + impl Value { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unknown => "UNKNOWN", + Self::FastCdc2020 => "FAST_CDC_2020", + Self::RepMaxCdc => "REP_MAX_CDC", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN" => Some(Self::Unknown), + "FAST_CDC_2020" => Some(Self::FastCdc2020), + "REP_MAX_CDC" => Some(Self::RepMaxCdc), + _ => None, + } + } + } +} /// Capabilities of the remote cache system. #[derive(Clone, PartialEq, ::prost::Message)] pub struct CacheCapabilities { @@ -1786,6 +1946,123 @@ pub struct CacheCapabilities { /// requests. #[prost(enumeration = "compressor::Value", repeated, tag = "7")] pub supported_batch_update_compressors: ::prost::alloc::vec::Vec, + /// The maximum blob size that the server will accept for CAS blob uploads. + /// - If it is 0, it means there is no limit set. A client may assume + /// arbitrarily large blobs may be uploaded to and downloaded from the cache. + /// - If it is larger than 0, implementations SHOULD NOT attempt to upload + /// blobs with size larger than the limit. Servers SHOULD reject blob + /// uploads over the `max_cas_blob_size_bytes` limit with response code + /// `INVALID_ARGUMENT` + /// - If the cache implementation returns a given limit, it MAY still serve + /// blobs larger than this limit. + #[prost(int64, tag = "8")] + pub max_cas_blob_size_bytes: i64, + /// Whether blob splitting is supported for the particular server/instance. If + /// yes, the server/instance implements the specified behavior for blob + /// splitting and a meaningful result can be expected from the + /// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// operation. + #[prost(bool, tag = "9")] + pub split_blob_support: bool, + /// Whether blob splicing is supported for the particular server/instance. If + /// yes, the server/instance implements the specified behavior for blob + /// splicing and a meaningful result can be expected from the + /// [ContentAddressableStorage.SpliceBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SpliceBlob] + /// operation. + #[prost(bool, tag = "10")] + pub splice_blob_support: bool, + /// The parameters for the FastCDC 2020 chunking algorithm. + /// If set, the server supports the FastCDC chunking algorithm. + #[prost(message, optional, tag = "11")] + pub fast_cdc_2020_params: ::core::option::Option, + /// The parameters for the RepMaxCDC chunking algorithm. + /// If set, the server supports the RepMaxCDC chunking algorithm. + #[prost(message, optional, tag = "12")] + pub rep_max_cdc_params: ::core::option::Option, +} +/// Parameters for the FastCDC content-defined chunking algorithm. +/// +/// Implementations MUST follow the FastCDC 2020 paper by Wen Xia, et al.: +/// +/// +/// Supported implementations: +/// - Rust: +/// - Go: +/// +/// Test vectors can be found in the accompanying fastcdc2020_test_vectors.txt file. +/// +/// Implementations MUST use normalization level 2, which has been found +/// successful for build artifacts with an average chunk size of 512 KiB. +/// +/// Key algorithm components from the paper: +/// +/// GEAR table: 256 64-bit integers for the rolling hash, computed as: +/// GEAR\[i\] = high_64_bits(MD5(byte(i))) for i in 0..255 +/// +/// MASKS table: Bit patterns for chunk boundary detection, derived from +/// the C reference implementation. The mask selection based on average +/// chunk size SHOULD match the paper. +/// +/// The minimum and maximum chunk sizes MUST be derived from the average: +/// - min_chunk_size = avg_chunk_size_bytes / 4 +/// - max_chunk_size = avg_chunk_size_bytes * 4 +/// +/// Blobs smaller than max_chunk_size (avg_chunk_size_bytes * 4) SHOULD be +/// uploaded without chunking. +/// +/// If any of the advertised parameters are not within the expected range, +/// the client SHOULD ignore FastCDC chunking function support. +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct FastCdc2020Params { + /// The average (expected) chunk size for the FastCDC chunking algorithm. + /// The value MUST be between 1 KiB and 1 MiB. The recommended value is + /// 524288 (512 KiB). + #[prost(uint64, tag = "1")] + pub avg_chunk_size_bytes: u64, + /// The seed for the FastCDC mask generation. + /// The recommended value is 0. + /// + /// All clients sharing a cache SHOULD use the same seed to maximize + /// chunk reuse. + #[prost(uint32, tag = "2")] + pub seed: u32, +} +/// Parameters for the RepMaxCDC content-defined chunking algorithm. +/// +/// Supported implementations: +/// - Go: +/// +/// Key algorithm components: +/// +/// GEAR table: 256 64-bit integers for the rolling hash, computed as: +/// GEAR\[i\] = high_64_bits(MD5(byte(i))) for i in 0..255 +/// +/// The algorithm repeatedly applies chunking until all chunks are in the +/// range [min_chunk_size_bytes, 2*min_chunk_size_bytes). Cutting points are +/// selected where the Gear rolling hash is maximized within a lookahead +/// window of horizon_size_bytes. +/// +/// For sufficiently large files, the average chunk size prior to +/// deduplication will approximately be min_chunk_size_bytes divided by +/// Rényi's parking constant (0.7475979203...). More details: +/// +/// +/// If any of the advertised parameters are not within the expected range, +/// the client SHOULD ignore RepMaxCDC chunking function support. +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] +pub struct RepMaxCdcParams { + /// The minimum chunk size for the RepMaxCDC chunking algorithm. + /// The value MUST be at least 64 bytes (the Gear hash window size). + /// All chunks will be in the range [min_chunk_size_bytes, 2*min_chunk_size_bytes). + /// The recommended value is 262144 (256 KiB). + #[prost(uint64, tag = "1")] + pub min_chunk_size_bytes: u64, + /// The lookahead window for finding optimal cutting points. + /// Larger values improve deduplication quality with diminishing returns. + /// Setting to 0 produces uniform chunks of min_chunk_size_bytes. + /// The recommended value is 8 * min_chunk_size_bytes. + #[prost(uint64, tag = "2")] + pub horizon_size_bytes: u64, } /// Capabilities of the remote execution system. #[derive(Clone, PartialEq, ::prost::Message)] @@ -1823,7 +2100,7 @@ pub struct ExecutionCapabilities { pub digest_functions: ::prost::alloc::vec::Vec, } /// Details for the tool used to call the API. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ToolDetails { /// Name of the tool, e.g. bazel. #[prost(string, tag = "1")] @@ -1845,7 +2122,7 @@ pub struct ToolDetails { /// Therefore, if the gRPC library is used to pass/retrieve this /// metadata, the user may ignore the base64 encoding and assume it is simply /// serialized as a binary message. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct RequestMetadata { /// The details for the tool invoking the requests. #[prost(message, optional, tag = "1")] @@ -2058,7 +2335,7 @@ pub mod execution_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/build.bazel.remote.execution.v2.Execution/Execute", ); @@ -2105,7 +2382,7 @@ pub mod execution_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/build.bazel.remote.execution.v2.Execution/WaitExecution", ); @@ -2121,8 +2398,8 @@ pub mod execution_client { } } } -/// Generated client implementations. -pub mod action_cache_client { +/// Generated server implementations. +pub mod execution_server { #![allow( unused_variables, dead_code, @@ -2131,384 +2408,174 @@ pub mod action_cache_client { clippy::let_unit_value, )] use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// The action cache API is used to query whether a given action has already been - /// performed and, if so, retrieve its result. Unlike the - /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage], - /// which addresses blobs by their own content, the action cache addresses the - /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] by a - /// digest of the encoded [Action][build.bazel.remote.execution.v2.Action] - /// which produced them. - /// - /// The lifetime of entries in the action cache is implementation-specific, but - /// the server SHOULD assume that more recently used entries are more likely to - /// be used again. - /// - /// As with other services in the Remote Execution API, any call may return an - /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing - /// information about when the client should retry the request; clients SHOULD - /// respect the information provided. - #[derive(Debug, Clone)] - pub struct ActionCacheClient { - inner: tonic::client::Grpc, - } - impl ActionCacheClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> ActionCacheClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, + /// Generated trait containing gRPC methods that should be implemented for use with ExecutionServer. + #[async_trait] + pub trait Execution: std::marker::Send + std::marker::Sync + 'static { + /// Server streaming response type for the Execute method. + type ExecuteStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result< + super::super::super::super::super::super::google::longrunning::Operation, + tonic::Status, >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, - { - ActionCacheClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. + > + + std::marker::Send + + 'static; + /// Execute an action remotely. /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. + /// In order to execute an action, the client must first upload all of the + /// inputs, the + /// [Command][build.bazel.remote.execution.v2.Command] to run, and the + /// [Action][build.bazel.remote.execution.v2.Action] into the + /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]. + /// It then calls `Execute` with an `action_digest` referring to them. The + /// server will run the action and eventually return the result. /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. + /// The input `Action`'s fields MUST meet the various canonicalization + /// requirements specified in the documentation for their types so that it has + /// the same digest as other logically equivalent `Action`s. The server MAY + /// enforce the requirements and return errors if a non-canonical input is + /// received. It MAY also proceed without verifying some or all of the + /// requirements, such as for performance reasons. If the server does not + /// verify the requirement, then it will treat the `Action` as distinct from + /// another logically equivalent action if they hash differently. /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// Retrieve a cached execution result. + /// Returns a stream of + /// [google.longrunning.Operation][google.longrunning.Operation] messages + /// describing the resulting execution, with eventual `response` + /// [ExecuteResponse][build.bazel.remote.execution.v2.ExecuteResponse]. The + /// `metadata` on the operation is of type + /// [ExecuteOperationMetadata][build.bazel.remote.execution.v2.ExecuteOperationMetadata]. /// - /// Implementations SHOULD ensure that any blobs referenced from the - /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage] - /// are available at the time of returning the - /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] and will be - /// for some period of time afterwards. The lifetimes of the referenced blobs SHOULD be increased - /// if necessary and applicable. + /// If the client remains connected after the first response is returned after + /// the server, then updates are streamed as if the client had called + /// [WaitExecution][build.bazel.remote.execution.v2.Execution.WaitExecution] + /// until the execution completes or the request reaches an error. The + /// operation can also be queried using [Operations + /// API][google.longrunning.Operations.GetOperation]. /// - /// Errors: + /// The server NEED NOT implement other methods or functionality of the + /// Operations API. /// - /// * `NOT_FOUND`: The requested `ActionResult` is not in the cache. - pub async fn get_action_result( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.ActionCache/GetActionResult", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "build.bazel.remote.execution.v2.ActionCache", - "GetActionResult", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Upload a new execution result. + /// Errors discovered during creation of the `Operation` will be reported + /// as gRPC Status errors, while errors that occurred while running the + /// action will be reported in the `status` field of the `ExecuteResponse`. The + /// server MUST NOT set the `error` field of the `Operation` proto. + /// The possible errors include: /// - /// In order to allow the server to perform access control based on the type of - /// action, and to assist with client debugging, the client MUST first upload - /// the [Action][build.bazel.remote.execution.v2.Execution] that produced the - /// result, along with its - /// [Command][build.bazel.remote.execution.v2.Command], into the - /// `ContentAddressableStorage`. + /// * `INVALID_ARGUMENT`: One or more arguments are invalid. + /// * `FAILED_PRECONDITION`: One or more errors occurred in setting up the + /// action requested, such as a missing input or command or no worker being + /// available. The client may be able to fix the errors and retry. + /// * `RESOURCE_EXHAUSTED`: There is insufficient quota of some resource to run + /// the action. + /// * `UNAVAILABLE`: Due to a transient condition, such as all workers being + /// occupied (and the server does not support a queue), the action could not + /// be started. The client should retry. + /// * `INTERNAL`: An internal error occurred in the execution engine or the + /// worker. + /// * `DEADLINE_EXCEEDED`: The execution timed out. + /// * `CANCELLED`: The operation was cancelled by the client. This status is + /// only possible if the server implements the Operations API CancelOperation + /// method, and it was called for the current execution. /// - /// Server implementations MAY modify the - /// `UpdateActionResultRequest.action_result` and return an equivalent value. + /// In the case of a missing input or command, the server SHOULD additionally + /// send a [PreconditionFailure][google.rpc.PreconditionFailure] error detail + /// where, for each requested blob not present in the CAS, there is a + /// `Violation` with a `type` of `MISSING` and a `subject` of + /// `"blobs/{digest_function/}{hash}/{size}"` indicating the digest of the + /// missing blob. The `subject` is formatted the same way as the + /// `resource_name` provided to + /// [ByteStream.Read][google.bytestream.ByteStream.Read], with the leading + /// instance name omitted. `digest_function` MUST thus be omitted if its value + /// is one of MD5, MURMUR3, SHA1, SHA256, SHA384, SHA512, or VSO. /// - /// Errors: + /// The server does not need to guarantee that a call to this method leads to + /// at most one execution of the action. The server MAY execute the action + /// multiple times, potentially in parallel. These redundant executions MAY + /// continue to run, even if the operation is completed. + async fn execute( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Server streaming response type for the WaitExecution method. + type WaitExecutionStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result< + super::super::super::super::super::super::google::longrunning::Operation, + tonic::Status, + >, + > + + std::marker::Send + + 'static; + /// Wait for an execution operation to complete. When the client initially + /// makes the request, the server immediately responds with the current status + /// of the execution. The server will leave the request stream open until the + /// operation completes, and then respond with the completed operation. The + /// server MAY choose to stream additional updates as execution progresses, + /// such as to provide an update as to the state of the execution. /// - /// * `INVALID_ARGUMENT`: One or more arguments are invalid. - /// * `FAILED_PRECONDITION`: One or more errors occurred in updating the - /// action result, such as a missing command or action. - /// * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the - /// entry to the cache. - pub async fn update_action_result( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.ActionCache/UpdateActionResult", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "build.bazel.remote.execution.v2.ActionCache", - "UpdateActionResult", - ), - ); - self.inner.unary(req, path, codec).await - } + /// In addition to the cases describe for Execute, the WaitExecution method + /// may fail as follows: + /// + /// * `NOT_FOUND`: The operation no longer exists due to any of a transient + /// condition, an unknown operation name, or if the server implements the + /// Operations API DeleteOperation method and it was called for the current + /// execution. The client should call `Execute` to retry. + async fn wait_execution( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } -} -/// Generated client implementations. -pub mod content_addressable_storage_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - /// The CAS (content-addressable storage) is used to store the inputs to and - /// outputs from the execution service. Each piece of content is addressed by the - /// digest of its binary data. - /// - /// Most of the binary data stored in the CAS is opaque to the execution engine, - /// and is only used as a communication medium. In order to build an - /// [Action][build.bazel.remote.execution.v2.Action], - /// however, the client will need to also upload the - /// [Command][build.bazel.remote.execution.v2.Command] and input root - /// [Directory][build.bazel.remote.execution.v2.Directory] for the Action. - /// The Command and Directory messages must be marshalled to wire format and then - /// uploaded under the hash as with any other piece of content. In practice, the - /// input root directory is likely to refer to other Directories in its - /// hierarchy, which must also each be uploaded on their own. - /// - /// For small file uploads the client should group them together and call - /// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]. - /// - /// For large uploads, the client must use the - /// [Write method][google.bytestream.ByteStream.Write] of the ByteStream API. - /// - /// For uncompressed data, The `WriteRequest.resource_name` is of the following form: - /// `{instance_name}/uploads/{uuid}/blobs/{digest_function/}{hash}/{size}{/optional_metadata}` - /// - /// Where: - /// * `instance_name` is an identifier used to distinguish between the various - /// instances on the server. Syntax and semantics of this field are defined - /// by the server; Clients must not make any assumptions about it (e.g., - /// whether it spans multiple path segments or not). If it is the empty path, - /// the leading slash is omitted, so that the `resource_name` becomes - /// `uploads/{uuid}/blobs/{digest_function/}{hash}/{size}{/optional_metadata}`. - /// To simplify parsing, a path segment cannot equal any of the following - /// keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations`, - /// `capabilities` or `compressed-blobs`. - /// * `uuid` is a version 4 UUID generated by the client, used to avoid - /// collisions between concurrent uploads of the same data. Clients MAY - /// reuse the same `uuid` for uploading different blobs. - /// * `digest_function` is a lowercase string form of a `DigestFunction.Value` - /// enum, indicating which digest function was used to compute `hash`. If the - /// digest function used is one of MD5, MURMUR3, SHA1, SHA256, SHA384, SHA512, - /// or VSO, this component MUST be omitted. In that case the server SHOULD - /// infer the digest function using the length of the `hash` and the digest - /// functions announced in the server's capabilities. - /// * `hash` and `size` refer to the [Digest][build.bazel.remote.execution.v2.Digest] - /// of the data being uploaded. - /// * `optional_metadata` is implementation specific data, which clients MAY omit. - /// Servers MAY ignore this metadata. - /// - /// Data can alternatively be uploaded in compressed form, with the following - /// `WriteRequest.resource_name` form: - /// `{instance_name}/uploads/{uuid}/compressed-blobs/{compressor}/{digest_function/}{uncompressed_hash}/{uncompressed_size}{/optional_metadata}` - /// - /// Where: - /// * `instance_name`, `uuid`, `digest_function` and `optional_metadata` are - /// defined as above. - /// * `compressor` is a lowercase string form of a `Compressor.Value` enum - /// other than `identity`, which is supported by the server and advertised in - /// [CacheCapabilities.supported_compressor][build.bazel.remote.execution.v2.CacheCapabilities.supported_compressor]. - /// * `uncompressed_hash` and `uncompressed_size` refer to the - /// [Digest][build.bazel.remote.execution.v2.Digest] of the data being - /// uploaded, once uncompressed. Servers MUST verify that these match - /// the uploaded data once uncompressed, and MUST return an - /// `INVALID_ARGUMENT` error in the case of mismatch. - /// - /// Note that when writing compressed blobs, the `WriteRequest.write_offset` in - /// the initial request in a stream refers to the offset in the uncompressed form - /// of the blob. In subsequent requests, `WriteRequest.write_offset` MUST be the - /// sum of the first request's 'WriteRequest.write_offset' and the total size of - /// all the compressed data bundles in the previous requests. - /// Note that this mixes an uncompressed offset with a compressed byte length, - /// which is nonsensical, but it is done to fit the semantics of the existing - /// ByteStream protocol. - /// - /// Uploads of the same data MAY occur concurrently in any form, compressed or - /// uncompressed. - /// - /// Clients SHOULD NOT use gRPC-level compression for ByteStream API `Write` - /// calls of compressed blobs, since this would compress already-compressed data. - /// - /// When attempting an upload, if another client has already completed the upload - /// (which may occur in the middle of a single upload if another client uploads - /// the same blob concurrently), the request will terminate immediately without - /// error, and with a response whose `committed_size` is the value `-1` if this - /// is a compressed upload, or with the full size of the uploaded file if this is - /// an uncompressed upload (regardless of how much data was transmitted by the - /// client). If the client completes the upload but the - /// [Digest][build.bazel.remote.execution.v2.Digest] does not match, an - /// `INVALID_ARGUMENT` error will be returned. In either case, the client should - /// not attempt to retry the upload. - /// - /// Small downloads can be grouped and requested in a batch via - /// [BatchReadBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchReadBlobs]. - /// - /// For large downloads, the client must use the - /// [Read method][google.bytestream.ByteStream.Read] of the ByteStream API. - /// - /// For uncompressed data, The `ReadRequest.resource_name` is of the following form: - /// `{instance_name}/blobs/{digest_function/}{hash}/{size}` - /// Where `instance_name`, `digest_function`, `hash` and `size` are defined as - /// for uploads. - /// - /// Data can alternatively be downloaded in compressed form, with the following - /// `ReadRequest.resource_name` form: - /// `{instance_name}/compressed-blobs/{compressor}/{digest_function/}{uncompressed_hash}/{uncompressed_size}` - /// - /// Where: - /// * `instance_name`, `compressor` and `digest_function` are defined as for - /// uploads. - /// * `uncompressed_hash` and `uncompressed_size` refer to the - /// [Digest][build.bazel.remote.execution.v2.Digest] of the data being - /// downloaded, once uncompressed. Clients MUST verify that these match - /// the downloaded data once uncompressed, and take appropriate steps in - /// the case of failure such as retrying a limited number of times or - /// surfacing an error to the user. - /// - /// When downloading compressed blobs: - /// * `ReadRequest.read_offset` refers to the offset in the uncompressed form - /// of the blob. - /// * Servers MUST return `INVALID_ARGUMENT` if `ReadRequest.read_limit` is - /// non-zero. - /// * Servers MAY use any compression level they choose, including different - /// levels for different blobs (e.g. choosing a level designed for maximum - /// speed for data known to be incompressible). - /// * Clients SHOULD NOT use gRPC-level compression, since this would compress - /// already-compressed data. - /// - /// Servers MUST be able to provide data for all recently advertised blobs in - /// each of the compression formats that the server supports, as well as in - /// uncompressed form. - /// - /// The lifetime of entries in the CAS is implementation specific, but it SHOULD - /// be long enough to allow for newly-added and recently looked-up entries to be - /// used in subsequent calls (e.g. to - /// [Execute][build.bazel.remote.execution.v2.Execution.Execute]). - /// - /// Servers MUST behave as though empty blobs are always available, even if they - /// have not been uploaded. Clients MAY optimize away the uploading or - /// downloading of empty blobs. + /// The Remote Execution API is used to execute an + /// [Action][build.bazel.remote.execution.v2.Action] on the remote + /// workers. /// /// As with other services in the Remote Execution API, any call may return an /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing /// information about when the client should retry the request; clients SHOULD /// respect the information provided. - #[derive(Debug, Clone)] - pub struct ContentAddressableStorageClient { - inner: tonic::client::Grpc, + #[derive(Debug)] + pub struct ExecutionServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, } - impl ContentAddressableStorageClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::Send, - { + impl ExecutionServer { pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } + Self::from_arc(Arc::new(inner)) } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } } pub fn with_interceptor( inner: T, interceptor: F, - ) -> ContentAddressableStorageClient> + ) -> InterceptedService where F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, { - ContentAddressableStorageClient::new( - InterceptedService::new(inner, interceptor), - ) + InterceptedService::new(Self::new(inner), interceptor) } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. + /// Enable decompressing requests with the given encoding. #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); self } - /// Enable decompressing responses. + /// Compress responses with the given encoding, if the client supports it. #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); self } /// Limits the maximum size of a decoded message. @@ -2516,7 +2583,7 @@ pub mod content_addressable_storage_client { /// Default: `4MB` #[must_use] pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); + self.max_decoding_message_size = Some(limit); self } /// Limits the maximum size of an encoded message. @@ -2524,204 +2591,161 @@ pub mod content_addressable_storage_client { /// Default: `usize::MAX` #[must_use] pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); + self.max_encoding_message_size = Some(limit); self } - /// Determine if blobs are present in the CAS. - /// - /// Clients can use this API before uploading blobs to determine which ones are - /// already present in the CAS and do not need to be uploaded again. - /// - /// Servers SHOULD increase the lifetimes of the referenced blobs if necessary and - /// applicable. - /// - /// There are no method-specific errors. - pub async fn find_missing_blobs( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.ContentAddressableStorage/FindMissingBlobs", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "build.bazel.remote.execution.v2.ContentAddressableStorage", - "FindMissingBlobs", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Upload many blobs at once. - /// - /// The server may enforce a limit of the combined total size of blobs - /// to be uploaded using this API. This limit may be obtained using the - /// [Capabilities][build.bazel.remote.execution.v2.Capabilities] API. - /// Requests exceeding the limit should either be split into smaller - /// chunks or uploaded using the - /// [ByteStream API][google.bytestream.ByteStream], as appropriate. - /// - /// This request is equivalent to calling a Bytestream `Write` request - /// on each individual blob, in parallel. The requests may succeed or fail - /// independently. - /// - /// Errors: - /// - /// * `INVALID_ARGUMENT`: The client attempted to upload more than the - /// server supported limit. - /// - /// Individual requests may return the following errors, additionally: - /// - /// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob. - /// * `INVALID_ARGUMENT`: The [Digest][build.bazel.remote.execution.v2.Digest] - /// does not match the provided data. - pub async fn batch_update_blobs( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.ContentAddressableStorage/BatchUpdateBlobs", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "build.bazel.remote.execution.v2.ContentAddressableStorage", - "BatchUpdateBlobs", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Download many blobs at once. - /// - /// The server may enforce a limit of the combined total size of blobs - /// to be downloaded using this API. This limit may be obtained using the - /// [Capabilities][build.bazel.remote.execution.v2.Capabilities] API. - /// Requests exceeding the limit should either be split into smaller - /// chunks or downloaded using the - /// [ByteStream API][google.bytestream.ByteStream], as appropriate. - /// - /// This request is equivalent to calling a Bytestream `Read` request - /// on each individual blob, in parallel. The requests may succeed or fail - /// independently. - /// - /// Errors: - /// - /// * `INVALID_ARGUMENT`: The client attempted to read more than the - /// server supported limit. - /// - /// Every error on individual read will be returned in the corresponding digest - /// status. - pub async fn batch_read_blobs( + } + impl tonic::codegen::Service> for ExecutionServer + where + T: Execution, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.ContentAddressableStorage/BatchReadBlobs", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "build.bazel.remote.execution.v2.ContentAddressableStorage", - "BatchReadBlobs", - ), - ); - self.inner.unary(req, path, codec).await + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) } - /// Fetch the entire directory tree rooted at a node. - /// - /// This request must be targeted at a - /// [Directory][build.bazel.remote.execution.v2.Directory] stored in the - /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage] - /// (CAS). The server will enumerate the `Directory` tree recursively and - /// return every node descended from the root. - /// - /// The GetTreeRequest.page_token parameter can be used to skip ahead in - /// the stream (e.g. when retrying a partially completed and aborted request), - /// by setting it to a value taken from GetTreeResponse.next_page_token of the - /// last successfully processed GetTreeResponse). - /// - /// The exact traversal order is unspecified and, unless retrieving subsequent - /// pages from an earlier request, is not guaranteed to be stable across - /// multiple invocations of `GetTree`. - /// - /// If part of the tree is missing from the CAS, the server will return the - /// portion present and omit the rest. - /// - /// Errors: - /// - /// * `NOT_FOUND`: The requested tree root is not present in the CAS. - pub async fn get_tree( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.ContentAddressableStorage/GetTree", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "build.bazel.remote.execution.v2.ContentAddressableStorage", - "GetTree", - ), - ); - self.inner.server_streaming(req, path, codec).await + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/build.bazel.remote.execution.v2.Execution/Execute" => { + #[allow(non_camel_case_types)] + struct ExecuteSvc(pub Arc); + impl< + T: Execution, + > tonic::server::ServerStreamingService + for ExecuteSvc { + type Response = super::super::super::super::super::super::google::longrunning::Operation; + type ResponseStream = T::ExecuteStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::execute(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ExecuteSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/build.bazel.remote.execution.v2.Execution/WaitExecution" => { + #[allow(non_camel_case_types)] + struct WaitExecutionSvc(pub Arc); + impl< + T: Execution, + > tonic::server::ServerStreamingService + for WaitExecutionSvc { + type Response = super::super::super::super::super::super::google::longrunning::Operation; + type ResponseStream = T::WaitExecutionStream; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::wait_execution(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = WaitExecutionSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.server_streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + let mut response = http::Response::new( + tonic::body::Body::default(), + ); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } + } } } + impl Clone for ExecutionServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "build.bazel.remote.execution.v2.Execution"; + impl tonic::server::NamedService for ExecutionServer { + const NAME: &'static str = SERVICE_NAME; + } } /// Generated client implementations. -pub mod capabilities_client { +pub mod action_cache_client { #![allow( unused_variables, dead_code, @@ -2731,17 +2755,27 @@ pub mod capabilities_client { )] use tonic::codegen::*; use tonic::codegen::http::Uri; - /// The Capabilities service may be used by remote execution clients to query - /// various server properties, in order to self-configure or return meaningful - /// error messages. + /// The action cache API is used to query whether a given action has already been + /// performed and, if so, retrieve its result. Unlike the + /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage], + /// which addresses blobs by their own content, the action cache addresses the + /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] by a + /// digest of the encoded [Action][build.bazel.remote.execution.v2.Action] + /// which produced them. /// - /// The query may include a particular `instance_name`, in which case the values - /// returned will pertain to that instance. + /// The lifetime of entries in the action cache is implementation-specific, but + /// the server SHOULD assume that more recently used entries are more likely to + /// be used again. + /// + /// As with other services in the Remote Execution API, any call may return an + /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing + /// information about when the client should retry the request; clients SHOULD + /// respect the information provided. #[derive(Debug, Clone)] - pub struct CapabilitiesClient { + pub struct ActionCacheClient { inner: tonic::client::Grpc, } - impl CapabilitiesClient + impl ActionCacheClient where T: tonic::client::GrpcService, T::Error: Into, @@ -2759,7 +2793,7 @@ pub mod capabilities_client { pub fn with_interceptor( inner: T, interceptor: F, - ) -> CapabilitiesClient> + ) -> ActionCacheClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, @@ -2773,7 +2807,7 @@ pub mod capabilities_client { http::Request, >>::Error: Into + std::marker::Send + std::marker::Sync, { - CapabilitiesClient::new(InterceptedService::new(inner, interceptor)) + ActionCacheClient::new(InterceptedService::new(inner, interceptor)) } /// Compress requests with the given encoding. /// @@ -2806,23 +2840,22 @@ pub mod capabilities_client { self.inner = self.inner.max_encoding_message_size(limit); self } - /// GetCapabilities returns the server capabilities configuration of the - /// remote endpoint. - /// Only the capabilities of the services supported by the endpoint will - /// be returned: - /// * Execution + CAS + Action Cache endpoints should return both - /// CacheCapabilities and ExecutionCapabilities. - /// * Execution only endpoints should return ExecutionCapabilities. - /// * CAS + Action Cache only endpoints should return CacheCapabilities. + /// Retrieve a cached execution result. /// - /// There are no method-specific errors. - pub async fn get_capabilities( + /// Implementations SHOULD ensure that any blobs referenced from the + /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage] + /// are available at the time of returning the + /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] and will be + /// for some period of time afterwards. The lifetimes of the referenced blobs SHOULD be increased + /// if necessary and applicable. + /// + /// Errors: + /// + /// * `NOT_FOUND`: The requested `ActionResult` is not in the cache. + pub async fn get_action_result( &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await @@ -2831,169 +2864,145 @@ pub mod capabilities_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/build.bazel.remote.execution.v2.Capabilities/GetCapabilities", + "/build.bazel.remote.execution.v2.ActionCache/GetActionResult", ); let mut req = request.into_request(); req.extensions_mut() .insert( GrpcMethod::new( - "build.bazel.remote.execution.v2.Capabilities", - "GetCapabilities", + "build.bazel.remote.execution.v2.ActionCache", + "GetActionResult", ), ); self.inner.unary(req, path, codec).await } - } -} -/// Generated server implementations. -pub mod execution_server { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with ExecutionServer. - #[async_trait] - pub trait Execution: std::marker::Send + std::marker::Sync + 'static { - /// Server streaming response type for the Execute method. - type ExecuteStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result< - super::super::super::super::super::super::google::longrunning::Operation, - tonic::Status, - >, - > - + std::marker::Send - + 'static; - /// Execute an action remotely. + /// Upload a new execution result. /// - /// In order to execute an action, the client must first upload all of the - /// inputs, the - /// [Command][build.bazel.remote.execution.v2.Command] to run, and the - /// [Action][build.bazel.remote.execution.v2.Action] into the - /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage]. - /// It then calls `Execute` with an `action_digest` referring to them. The - /// server will run the action and eventually return the result. + /// In order to allow the server to perform access control based on the type of + /// action, and to assist with client debugging, the client MUST first upload + /// the [Action][build.bazel.remote.execution.v2.Execution] that produced the + /// result, along with its + /// [Command][build.bazel.remote.execution.v2.Command], into the + /// `ContentAddressableStorage`. /// - /// The input `Action`'s fields MUST meet the various canonicalization - /// requirements specified in the documentation for their types so that it has - /// the same digest as other logically equivalent `Action`s. The server MAY - /// enforce the requirements and return errors if a non-canonical input is - /// received. It MAY also proceed without verifying some or all of the - /// requirements, such as for performance reasons. If the server does not - /// verify the requirement, then it will treat the `Action` as distinct from - /// another logically equivalent action if they hash differently. + /// Server implementations MAY modify the + /// `UpdateActionResultRequest.action_result` and return an equivalent value. /// - /// Returns a stream of - /// [google.longrunning.Operation][google.longrunning.Operation] messages - /// describing the resulting execution, with eventual `response` - /// [ExecuteResponse][build.bazel.remote.execution.v2.ExecuteResponse]. The - /// `metadata` on the operation is of type - /// [ExecuteOperationMetadata][build.bazel.remote.execution.v2.ExecuteOperationMetadata]. + /// Errors: /// - /// If the client remains connected after the first response is returned after - /// the server, then updates are streamed as if the client had called - /// [WaitExecution][build.bazel.remote.execution.v2.Execution.WaitExecution] - /// until the execution completes or the request reaches an error. The - /// operation can also be queried using [Operations - /// API][google.longrunning.Operations.GetOperation]. + /// * `INVALID_ARGUMENT`: One or more arguments are invalid. + /// * `FAILED_PRECONDITION`: One or more errors occurred in updating the + /// action result, such as a missing command or action. + /// * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the + /// entry to the cache. + pub async fn update_action_result( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ActionCache/UpdateActionResult", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ActionCache", + "UpdateActionResult", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod action_cache_server { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with ActionCacheServer. + #[async_trait] + pub trait ActionCache: std::marker::Send + std::marker::Sync + 'static { + /// Retrieve a cached execution result. /// - /// The server NEED NOT implement other methods or functionality of the - /// Operations API. + /// Implementations SHOULD ensure that any blobs referenced from the + /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage] + /// are available at the time of returning the + /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] and will be + /// for some period of time afterwards. The lifetimes of the referenced blobs SHOULD be increased + /// if necessary and applicable. /// - /// Errors discovered during creation of the `Operation` will be reported - /// as gRPC Status errors, while errors that occurred while running the - /// action will be reported in the `status` field of the `ExecuteResponse`. The - /// server MUST NOT set the `error` field of the `Operation` proto. - /// The possible errors include: + /// Errors: /// - /// * `INVALID_ARGUMENT`: One or more arguments are invalid. - /// * `FAILED_PRECONDITION`: One or more errors occurred in setting up the - /// action requested, such as a missing input or command or no worker being - /// available. The client may be able to fix the errors and retry. - /// * `RESOURCE_EXHAUSTED`: There is insufficient quota of some resource to run - /// the action. - /// * `UNAVAILABLE`: Due to a transient condition, such as all workers being - /// occupied (and the server does not support a queue), the action could not - /// be started. The client should retry. - /// * `INTERNAL`: An internal error occurred in the execution engine or the - /// worker. - /// * `DEADLINE_EXCEEDED`: The execution timed out. - /// * `CANCELLED`: The operation was cancelled by the client. This status is - /// only possible if the server implements the Operations API CancelOperation - /// method, and it was called for the current execution. + /// * `NOT_FOUND`: The requested `ActionResult` is not in the cache. + async fn get_action_result( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Upload a new execution result. /// - /// In the case of a missing input or command, the server SHOULD additionally - /// send a [PreconditionFailure][google.rpc.PreconditionFailure] error detail - /// where, for each requested blob not present in the CAS, there is a - /// `Violation` with a `type` of `MISSING` and a `subject` of - /// `"blobs/{digest_function/}{hash}/{size}"` indicating the digest of the - /// missing blob. The `subject` is formatted the same way as the - /// `resource_name` provided to - /// [ByteStream.Read][google.bytestream.ByteStream.Read], with the leading - /// instance name omitted. `digest_function` MUST thus be omitted if its value - /// is one of MD5, MURMUR3, SHA1, SHA256, SHA384, SHA512, or VSO. + /// In order to allow the server to perform access control based on the type of + /// action, and to assist with client debugging, the client MUST first upload + /// the [Action][build.bazel.remote.execution.v2.Execution] that produced the + /// result, along with its + /// [Command][build.bazel.remote.execution.v2.Command], into the + /// `ContentAddressableStorage`. /// - /// The server does not need to guarantee that a call to this method leads to - /// at most one execution of the action. The server MAY execute the action - /// multiple times, potentially in parallel. These redundant executions MAY - /// continue to run, even if the operation is completed. - async fn execute( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Server streaming response type for the WaitExecution method. - type WaitExecutionStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result< - super::super::super::super::super::super::google::longrunning::Operation, - tonic::Status, - >, - > - + std::marker::Send - + 'static; - /// Wait for an execution operation to complete. When the client initially - /// makes the request, the server immediately responds with the current status - /// of the execution. The server will leave the request stream open until the - /// operation completes, and then respond with the completed operation. The - /// server MAY choose to stream additional updates as execution progresses, - /// such as to provide an update as to the state of the execution. + /// Server implementations MAY modify the + /// `UpdateActionResultRequest.action_result` and return an equivalent value. /// - /// In addition to the cases describe for Execute, the WaitExecution method - /// may fail as follows: + /// Errors: /// - /// * `NOT_FOUND`: The operation no longer exists due to any of a transient - /// condition, an unknown operation name, or if the server implements the - /// Operations API DeleteOperation method and it was called for the current - /// execution. The client should call `Execute` to retry. - async fn wait_execution( + /// * `INVALID_ARGUMENT`: One or more arguments are invalid. + /// * `FAILED_PRECONDITION`: One or more errors occurred in updating the + /// action result, such as a missing command or action. + /// * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the + /// entry to the cache. + async fn update_action_result( &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; } - /// The Remote Execution API is used to execute an - /// [Action][build.bazel.remote.execution.v2.Action] on the remote - /// workers. + /// The action cache API is used to query whether a given action has already been + /// performed and, if so, retrieve its result. Unlike the + /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage], + /// which addresses blobs by their own content, the action cache addresses the + /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] by a + /// digest of the encoded [Action][build.bazel.remote.execution.v2.Action] + /// which produced them. + /// + /// The lifetime of entries in the action cache is implementation-specific, but + /// the server SHOULD assume that more recently used entries are more likely to + /// be used again. /// /// As with other services in the Remote Execution API, any call may return an /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing /// information about when the client should retry the request; clients SHOULD /// respect the information provided. #[derive(Debug)] - pub struct ExecutionServer { + pub struct ActionCacheServer { inner: Arc, accept_compression_encodings: EnabledCompressionEncodings, send_compression_encodings: EnabledCompressionEncodings, max_decoding_message_size: Option, max_encoding_message_size: Option, } - impl ExecutionServer { + impl ActionCacheServer { pub fn new(inner: T) -> Self { Self::from_arc(Arc::new(inner)) } @@ -3044,9 +3053,9 @@ pub mod execution_server { self } } - impl tonic::codegen::Service> for ExecutionServer + impl tonic::codegen::Service> for ActionCacheServer where - T: Execution, + T: ActionCache, B: Body + std::marker::Send + 'static, B::Error: Into + std::marker::Send + 'static, { @@ -3061,26 +3070,25 @@ pub mod execution_server { } fn call(&mut self, req: http::Request) -> Self::Future { match req.uri().path() { - "/build.bazel.remote.execution.v2.Execution/Execute" => { + "/build.bazel.remote.execution.v2.ActionCache/GetActionResult" => { #[allow(non_camel_case_types)] - struct ExecuteSvc(pub Arc); + struct GetActionResultSvc(pub Arc); impl< - T: Execution, - > tonic::server::ServerStreamingService - for ExecuteSvc { - type Response = super::super::super::super::super::super::google::longrunning::Operation; - type ResponseStream = T::ExecuteStream; + T: ActionCache, + > tonic::server::UnaryService + for GetActionResultSvc { + type Response = super::ActionResult; type Future = BoxFuture< - tonic::Response, + tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::execute(&inner, request).await + ::get_action_result(&inner, request).await }; Box::pin(fut) } @@ -3091,8 +3099,8 @@ pub mod execution_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ExecuteSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let method = GetActionResultSvc(inner); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -3102,31 +3110,31 @@ pub mod execution_server { max_decoding_message_size, max_encoding_message_size, ); - let res = grpc.server_streaming(method, req).await; + let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) } - "/build.bazel.remote.execution.v2.Execution/WaitExecution" => { + "/build.bazel.remote.execution.v2.ActionCache/UpdateActionResult" => { #[allow(non_camel_case_types)] - struct WaitExecutionSvc(pub Arc); + struct UpdateActionResultSvc(pub Arc); impl< - T: Execution, - > tonic::server::ServerStreamingService - for WaitExecutionSvc { - type Response = super::super::super::super::super::super::google::longrunning::Operation; - type ResponseStream = T::WaitExecutionStream; + T: ActionCache, + > tonic::server::UnaryService + for UpdateActionResultSvc { + type Response = super::ActionResult; type Future = BoxFuture< - tonic::Response, + tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::wait_execution(&inner, request).await + ::update_action_result(&inner, request) + .await }; Box::pin(fut) } @@ -3137,8 +3145,8 @@ pub mod execution_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = WaitExecutionSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let method = UpdateActionResultSvc(inner); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -3148,7 +3156,7 @@ pub mod execution_server { max_decoding_message_size, max_encoding_message_size, ); - let res = grpc.server_streaming(method, req).await; + let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) @@ -3175,7 +3183,7 @@ pub mod execution_server { } } } - impl Clone for ExecutionServer { + impl Clone for ActionCacheServer { fn clone(&self) -> Self { let inner = self.inner.clone(); Self { @@ -3188,13 +3196,13 @@ pub mod execution_server { } } /// Generated gRPC service name - pub const SERVICE_NAME: &str = "build.bazel.remote.execution.v2.Execution"; - impl tonic::server::NamedService for ExecutionServer { + pub const SERVICE_NAME: &str = "build.bazel.remote.execution.v2.ActionCache"; + impl tonic::server::NamedService for ActionCacheServer { const NAME: &'static str = SERVICE_NAME; } } -/// Generated server implementations. -pub mod action_cache_server { +/// Generated client implementations. +pub mod content_addressable_storage_client { #![allow( unused_variables, dead_code, @@ -3203,271 +3211,582 @@ pub mod action_cache_server { clippy::let_unit_value, )] use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with ActionCacheServer. - #[async_trait] - pub trait ActionCache: std::marker::Send + std::marker::Sync + 'static { - /// Retrieve a cached execution result. + use tonic::codegen::http::Uri; + /// The CAS (content-addressable storage) is used to store the inputs to and + /// outputs from the execution service. Each piece of content is addressed by the + /// digest of its binary data. + /// + /// Most of the binary data stored in the CAS is opaque to the execution engine, + /// and is only used as a communication medium. In order to build an + /// [Action][build.bazel.remote.execution.v2.Action], + /// however, the client will need to also upload the + /// [Command][build.bazel.remote.execution.v2.Command] and input root + /// [Directory][build.bazel.remote.execution.v2.Directory] for the Action. + /// The Command and Directory messages must be marshalled to wire format and then + /// uploaded under the hash as with any other piece of content. In practice, the + /// input root directory is likely to refer to other Directories in its + /// hierarchy, which must also each be uploaded on their own. + /// + /// For small file uploads the client should group them together and call + /// [BatchUpdateBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchUpdateBlobs]. + /// + /// For large uploads, the client must use the + /// [Write method][google.bytestream.ByteStream.Write] of the ByteStream API. + /// + /// For uncompressed data, The `WriteRequest.resource_name` is of the following form: + /// `{instance_name}/uploads/{uuid}/blobs/{digest_function/}{hash}/{size}{/optional_metadata}` + /// + /// Where: + /// * `instance_name` is an identifier used to distinguish between the various + /// instances on the server. Syntax and semantics of this field are defined + /// by the server; Clients must not make any assumptions about it (e.g., + /// whether it spans multiple path segments or not). If it is the empty path, + /// the leading slash is omitted, so that the `resource_name` becomes + /// `uploads/{uuid}/blobs/{digest_function/}{hash}/{size}{/optional_metadata}`. + /// To simplify parsing, a path segment cannot equal any of the following + /// keywords: `blobs`, `uploads`, `actions`, `actionResults`, `operations`, + /// `capabilities` or `compressed-blobs`. + /// * `uuid` is a version 4 UUID generated by the client, used to avoid + /// collisions between concurrent uploads of the same data. Clients MAY + /// reuse the same `uuid` for uploading different blobs. + /// * `digest_function` is a lowercase string form of a `DigestFunction.Value` + /// enum, indicating which digest function was used to compute `hash`. If the + /// digest function used is one of MD5, MURMUR3, SHA1, SHA256, SHA384, SHA512, + /// or VSO, this component MUST be omitted. In that case the server SHOULD + /// infer the digest function using the length of the `hash` and the digest + /// functions announced in the server's capabilities. + /// * `hash` and `size` refer to the [Digest][build.bazel.remote.execution.v2.Digest] + /// of the data being uploaded. + /// * `optional_metadata` is implementation specific data, which clients MAY omit. + /// Servers MAY ignore this metadata. + /// + /// Data can alternatively be uploaded in compressed form, with the following + /// `WriteRequest.resource_name` form: + /// `{instance_name}/uploads/{uuid}/compressed-blobs/{compressor}/{digest_function/}{uncompressed_hash}/{uncompressed_size}{/optional_metadata}` + /// + /// Where: + /// * `instance_name`, `uuid`, `digest_function` and `optional_metadata` are + /// defined as above. + /// * `compressor` is a lowercase string form of a `Compressor.Value` enum + /// other than `identity`, which is supported by the server and advertised in + /// [CacheCapabilities.supported_compressor][build.bazel.remote.execution.v2.CacheCapabilities.supported_compressor]. + /// * `uncompressed_hash` and `uncompressed_size` refer to the + /// [Digest][build.bazel.remote.execution.v2.Digest] of the data being + /// uploaded, once uncompressed. Servers MUST verify that these match + /// the uploaded data once uncompressed, and MUST return an + /// `INVALID_ARGUMENT` error in the case of mismatch. + /// + /// Note that when writing compressed blobs, the `WriteRequest.write_offset` in + /// the initial request in a stream refers to the offset in the uncompressed form + /// of the blob. In subsequent requests, `WriteRequest.write_offset` MUST be the + /// sum of the first request's 'WriteRequest.write_offset' and the total size of + /// all the compressed data bundles in the previous requests. + /// Note that this mixes an uncompressed offset with a compressed byte length, + /// which is nonsensical, but it is done to fit the semantics of the existing + /// ByteStream protocol. + /// + /// Uploads of the same data MAY occur concurrently in any form, compressed or + /// uncompressed. + /// + /// Clients SHOULD NOT use gRPC-level compression for ByteStream API `Write` + /// calls of compressed blobs, since this would compress already-compressed data. + /// + /// When attempting an upload, if another client has already completed the upload + /// (which may occur in the middle of a single upload if another client uploads + /// the same blob concurrently), the request will terminate immediately without + /// error, and with a response whose `committed_size` is the value `-1` if this + /// is a compressed upload, or with the full size of the uploaded file if this is + /// an uncompressed upload (regardless of how much data was transmitted by the + /// client). If the client completes the upload but the + /// [Digest][build.bazel.remote.execution.v2.Digest] does not match, an + /// `INVALID_ARGUMENT` error will be returned. In either case, the client should + /// not attempt to retry the upload. + /// + /// Small downloads can be grouped and requested in a batch via + /// [BatchReadBlobs][build.bazel.remote.execution.v2.ContentAddressableStorage.BatchReadBlobs]. + /// + /// For large downloads, the client must use the + /// [Read method][google.bytestream.ByteStream.Read] of the ByteStream API. + /// + /// For uncompressed data, The `ReadRequest.resource_name` is of the following form: + /// `{instance_name}/blobs/{digest_function/}{hash}/{size}` + /// Where `instance_name`, `digest_function`, `hash` and `size` are defined as + /// for uploads. + /// + /// Data can alternatively be downloaded in compressed form, with the following + /// `ReadRequest.resource_name` form: + /// `{instance_name}/compressed-blobs/{compressor}/{digest_function/}{uncompressed_hash}/{uncompressed_size}` + /// + /// Where: + /// * `instance_name`, `compressor` and `digest_function` are defined as for + /// uploads. + /// * `uncompressed_hash` and `uncompressed_size` refer to the + /// [Digest][build.bazel.remote.execution.v2.Digest] of the data being + /// downloaded, once uncompressed. Clients MUST verify that these match + /// the downloaded data once uncompressed, and take appropriate steps in + /// the case of failure such as retrying a limited number of times or + /// surfacing an error to the user. + /// + /// When downloading compressed blobs: + /// * `ReadRequest.read_offset` refers to the offset in the uncompressed form + /// of the blob. + /// * Servers MUST return `INVALID_ARGUMENT` if `ReadRequest.read_limit` is + /// non-zero. + /// * Servers MAY use any compression level they choose, including different + /// levels for different blobs (e.g. choosing a level designed for maximum + /// speed for data known to be incompressible). + /// * Clients SHOULD NOT use gRPC-level compression, since this would compress + /// already-compressed data. + /// + /// Servers MUST be able to provide data for all recently advertised blobs in + /// each of the compression formats that the server supports, as well as in + /// uncompressed form. + /// + /// The lifetime of entries in the CAS is implementation specific, but it SHOULD + /// be long enough to allow for newly-added and recently looked-up entries to be + /// used in subsequent calls (e.g. to + /// [Execute][build.bazel.remote.execution.v2.Execution.Execute]). + /// + /// Servers MUST behave as though empty blobs are always available, even if they + /// have not been uploaded. Clients MAY optimize away the uploading or + /// downloading of empty blobs. + /// + /// As with other services in the Remote Execution API, any call may return an + /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing + /// information about when the client should retry the request; clients SHOULD + /// respect the information provided. + #[derive(Debug, Clone)] + pub struct ContentAddressableStorageClient { + inner: tonic::client::Grpc, + } + impl ContentAddressableStorageClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> ContentAddressableStorageClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + ContentAddressableStorageClient::new( + InterceptedService::new(inner, interceptor), + ) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Determine if blobs are present in the CAS. + /// + /// Clients can use this API before uploading blobs to determine which ones are + /// already present in the CAS and do not need to be uploaded again. + /// + /// Servers SHOULD increase the lifetimes of the referenced blobs if necessary and + /// applicable. + /// + /// There are no method-specific errors. + pub async fn find_missing_blobs( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/FindMissingBlobs", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "FindMissingBlobs", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Upload many blobs at once. + /// + /// The server may enforce a limit of the combined total size of blobs + /// to be uploaded using this API. This limit may be obtained using the + /// [Capabilities][build.bazel.remote.execution.v2.Capabilities] API. + /// Requests exceeding the limit should either be split into smaller + /// chunks or uploaded using the + /// [ByteStream API][google.bytestream.ByteStream], as appropriate. + /// + /// This request is equivalent to calling a Bytestream `Write` request + /// on each individual blob, in parallel. The requests may succeed or fail + /// independently. + /// + /// Errors: + /// + /// * `INVALID_ARGUMENT`: The client attempted to upload more than the + /// server supported limit. + /// + /// Individual requests may return the following errors, additionally: + /// + /// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob. + /// * `INVALID_ARGUMENT`: The [Digest][build.bazel.remote.execution.v2.Digest] + /// does not match the provided data. + pub async fn batch_update_blobs( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/BatchUpdateBlobs", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "BatchUpdateBlobs", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Download many blobs at once. + /// + /// The server may enforce a limit of the combined total size of blobs + /// to be downloaded using this API. This limit may be obtained using the + /// [Capabilities][build.bazel.remote.execution.v2.Capabilities] API. + /// Requests exceeding the limit should either be split into smaller + /// chunks or downloaded using the + /// [ByteStream API][google.bytestream.ByteStream], as appropriate. + /// + /// This request is equivalent to calling a Bytestream `Read` request + /// on each individual blob, in parallel. The requests may succeed or fail + /// independently. + /// + /// Errors: + /// + /// * `INVALID_ARGUMENT`: The client attempted to read more than the + /// server supported limit. + /// + /// Every error on individual read will be returned in the corresponding digest + /// status. + pub async fn batch_read_blobs( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/BatchReadBlobs", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "BatchReadBlobs", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Fetch the entire directory tree rooted at a node. + /// + /// This request must be targeted at a + /// [Directory][build.bazel.remote.execution.v2.Directory] stored in the + /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage] + /// (CAS). The server will enumerate the `Directory` tree recursively and + /// return every node descended from the root. + /// + /// The GetTreeRequest.page_token parameter can be used to skip ahead in + /// the stream (e.g. when retrying a partially completed and aborted request), + /// by setting it to a value taken from GetTreeResponse.next_page_token of the + /// last successfully processed GetTreeResponse). + /// + /// The exact traversal order is unspecified and, unless retrieving subsequent + /// pages from an earlier request, is not guaranteed to be stable across + /// multiple invocations of `GetTree`. + /// + /// If part of the tree is missing from the CAS, the server will return the + /// portion present and omit the rest. + /// + /// Errors: + /// + /// * `NOT_FOUND`: The requested tree root is not present in the CAS. + pub async fn get_tree( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/GetTree", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "GetTree", + ), + ); + self.inner.server_streaming(req, path, codec).await + } + /// SplitBlob retrieves information about how a blob is split into chunks. + /// + /// This call returns information about how a blob is split into chunks, and + /// returns a list of the chunk digests. Using the returned list of chunk digests, + /// a client can check which chunks are locally available and only fetch the + /// missing ones. The desired blob can be assembled by concatenating the fetched + /// chunks in the order of the digests in the list. The chunks SHOULD all be + /// available in the CAS. + /// + /// This API can be used to reduce the required data to download a large blob + /// from CAS if some chunks from similar blobs are locally available. For this + /// procedure to work properly, blobs SHOULD be split in a content-defined way, + /// rather than with fixed-sized chunking. + /// + /// If a split request is answered successfully, a client can expect the + /// following guarantees from the server: + /// 1. The blob chunks are stored in CAS. + /// 2. Concatenating the blob chunks in the order of the digest list returned + /// by the server results in the original blob. + /// + /// Servers which implement this functionality MUST declare that they support + /// it by setting the + /// [CacheCapabilities.split_blob_support][build.bazel.remote.execution.v2.CacheCapabilities.split_blob_support] + /// field accordingly. + /// + /// Clients MUST check that the server supports this capability, before using + /// it. + /// + /// Clients SHOULD verify that the digest of the blob assembled by the fetched + /// chunks is equal to the requested blob digest. + /// + /// The lifetimes of the generated chunk blobs MAY be independent of the + /// lifetime of the original blob. In particular: + /// * A blob and any chunk derived from it MAY be evicted from the CAS at + /// different times. + /// * A call to [SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// extends the lifetime of the original blob, and sets the lifetimes of + /// the resulting chunks (or extends the lifetimes of already-existing + /// chunks). + /// * Touching a chunk extends its lifetime, but the server MAY choose not + /// to extend the lifetime of the original blob. + /// * Touching the original blob extends its lifetime, but the server MAY + /// choose not to extend the lifetimes of chunks derived from it. + /// + /// When blob splitting and splicing is used at the same time, the clients and + /// the server SHOULD agree out-of-band upon a chunking algorithm used by both + /// parties to benefit from each other's chunk data and avoid unnecessary data + /// duplication. + /// + /// Errors: + /// + /// * `NOT_FOUND`: The requested blob is not present in the CAS, OR there is no + /// split information available for the blob, OR at least one chunk needed to + /// reconstruct the blob is missing from the CAS. + /// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob + /// chunks. + pub async fn split_blob( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/SplitBlob", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "SplitBlob", + ), + ); + self.inner.unary(req, path, codec).await + } + /// SpliceBlob tells the CAS how chunks can compose a blob. /// - /// Implementations SHOULD ensure that any blobs referenced from the - /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage] - /// are available at the time of returning the - /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] and will be - /// for some period of time afterwards. The lifetimes of the referenced blobs SHOULD be increased - /// if necessary and applicable. + /// This is the complementary operation to the + /// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// function to handle the chunked upload of large blobs to save upload + /// traffic. /// - /// Errors: + /// When uploading a large blob using chunked upload, clients MUST first upload + /// all chunks to the CAS, then call this RPC to tell the server how those chunks + /// compose the original blob. The chunks referenced in the SpliceBlob call SHOULD be + /// available in the CAS before calling this RPC. /// - /// * `NOT_FOUND`: The requested `ActionResult` is not in the cache. - async fn get_action_result( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Upload a new execution result. + /// If a client needs to upload a large blob and is able to split a blob into + /// chunks in such a way that reusable chunks are obtained, e.g., by means of + /// content-defined chunking, it can first determine which parts of the blob + /// are already available in the remote CAS and upload the missing chunks, and + /// then use this API to store information on how the chunks compose the + /// original blob. /// - /// In order to allow the server to perform access control based on the type of - /// action, and to assist with client debugging, the client MUST first upload - /// the [Action][build.bazel.remote.execution.v2.Execution] that produced the - /// result, along with its - /// [Command][build.bazel.remote.execution.v2.Command], into the - /// `ContentAddressableStorage`. + /// Servers which implement this functionality MUST declare that they support + /// it by setting the + /// [CacheCapabilities.splice_blob_support][build.bazel.remote.execution.v2.CacheCapabilities.splice_blob_support] + /// field accordingly. /// - /// Server implementations MAY modify the - /// `UpdateActionResultRequest.action_result` and return an equivalent value. + /// Clients MUST check that the server supports this capability, before using + /// it. /// - /// Errors: + /// In order to ensure data consistency of the CAS, the server MUST only add + /// blobs to the CAS after verifying their digests. In particular, servers MUST NOT + /// trust digests provided by the client. The server MAY accept a request as no-op + /// if the client-specified blob is already in CAS or if information on how to + /// construct the blob from chunks is available. If the client-specified blob is + /// not already in the CAS, the server MUST verify that the digest of the newly + /// created blob assembled from chunks matches the digest specified by the + /// client, and reject the request if they differ. Servers MAY choose to allow + /// overwriting existing chunk mappings or to store multiple chunk mappings for + /// the same blob. /// - /// * `INVALID_ARGUMENT`: One or more arguments are invalid. - /// * `FAILED_PRECONDITION`: One or more errors occurred in updating the - /// action result, such as a missing command or action. - /// * `RESOURCE_EXHAUSTED`: There is insufficient storage space to add the - /// entry to the cache. - async fn update_action_result( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - } - /// The action cache API is used to query whether a given action has already been - /// performed and, if so, retrieve its result. Unlike the - /// [ContentAddressableStorage][build.bazel.remote.execution.v2.ContentAddressableStorage], - /// which addresses blobs by their own content, the action cache addresses the - /// [ActionResult][build.bazel.remote.execution.v2.ActionResult] by a - /// digest of the encoded [Action][build.bazel.remote.execution.v2.Action] - /// which produced them. - /// - /// The lifetime of entries in the action cache is implementation-specific, but - /// the server SHOULD assume that more recently used entries are more likely to - /// be used again. - /// - /// As with other services in the Remote Execution API, any call may return an - /// error with a [RetryInfo][google.rpc.RetryInfo] error detail providing - /// information about when the client should retry the request; clients SHOULD - /// respect the information provided. - #[derive(Debug)] - pub struct ActionCacheServer { - inner: Arc, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - impl ActionCacheServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. + /// When blob splitting and splicing is used at the same time, the clients and + /// the server SHOULD agree out-of-band upon a chunking algorithm used by both + /// parties to benefit from each other's chunk data and avoid unnecessary data + /// duplication. /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. + /// Errors: /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for ActionCacheServer - where - T: ActionCache, - B: Body + std::marker::Send + 'static, - B::Error: Into + std::marker::Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( + /// * `NOT_FOUND`: At least one of the blob chunks is not present in the CAS. + /// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the + /// spliced blob. + /// * `INVALID_ARGUMENT`: The digest of the spliced blob is different from the + /// provided expected digest. + /// * `ALREADY_EXISTS`: The blob already exists in CAS and the server did not + /// extend the lifetime of the chunks specified in the request, e.g. because + /// it prefers a different chunking and extended those instead. Clients can + /// call [SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// to check what chunk mapping the server is using. + pub async fn splice_blob( &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - match req.uri().path() { - "/build.bazel.remote.execution.v2.ActionCache/GetActionResult" => { - #[allow(non_camel_case_types)] - struct GetActionResultSvc(pub Arc); - impl< - T: ActionCache, - > tonic::server::UnaryService - for GetActionResultSvc { - type Response = super::ActionResult; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_action_result(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetActionResultSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/build.bazel.remote.execution.v2.ActionCache/UpdateActionResult" => { - #[allow(non_camel_case_types)] - struct UpdateActionResultSvc(pub Arc); - impl< - T: ActionCache, - > tonic::server::UnaryService - for UpdateActionResultSvc { - type Response = super::ActionResult; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::update_action_result(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = UpdateActionResultSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => { - Box::pin(async move { - let mut response = http::Response::new( - tonic::body::Body::default(), - ); - let headers = response.headers_mut(); - headers - .insert( - tonic::Status::GRPC_STATUS, - (tonic::Code::Unimplemented as i32).into(), - ); - headers - .insert( - http::header::CONTENT_TYPE, - tonic::metadata::GRPC_CONTENT_TYPE, - ); - Ok(response) - }) - } - } - } - } - impl Clone for ActionCacheServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/SpliceBlob", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "SpliceBlob", + ), + ); + self.inner.unary(req, path, codec).await } } - /// Generated gRPC service name - pub const SERVICE_NAME: &str = "build.bazel.remote.execution.v2.ActionCache"; - impl tonic::server::NamedService for ActionCacheServer { - const NAME: &'static str = SERVICE_NAME; - } } /// Generated server implementations. pub mod content_addressable_storage_server { @@ -3588,6 +3907,131 @@ pub mod content_addressable_storage_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + /// SplitBlob retrieves information about how a blob is split into chunks. + /// + /// This call returns information about how a blob is split into chunks, and + /// returns a list of the chunk digests. Using the returned list of chunk digests, + /// a client can check which chunks are locally available and only fetch the + /// missing ones. The desired blob can be assembled by concatenating the fetched + /// chunks in the order of the digests in the list. The chunks SHOULD all be + /// available in the CAS. + /// + /// This API can be used to reduce the required data to download a large blob + /// from CAS if some chunks from similar blobs are locally available. For this + /// procedure to work properly, blobs SHOULD be split in a content-defined way, + /// rather than with fixed-sized chunking. + /// + /// If a split request is answered successfully, a client can expect the + /// following guarantees from the server: + /// 1. The blob chunks are stored in CAS. + /// 2. Concatenating the blob chunks in the order of the digest list returned + /// by the server results in the original blob. + /// + /// Servers which implement this functionality MUST declare that they support + /// it by setting the + /// [CacheCapabilities.split_blob_support][build.bazel.remote.execution.v2.CacheCapabilities.split_blob_support] + /// field accordingly. + /// + /// Clients MUST check that the server supports this capability, before using + /// it. + /// + /// Clients SHOULD verify that the digest of the blob assembled by the fetched + /// chunks is equal to the requested blob digest. + /// + /// The lifetimes of the generated chunk blobs MAY be independent of the + /// lifetime of the original blob. In particular: + /// * A blob and any chunk derived from it MAY be evicted from the CAS at + /// different times. + /// * A call to [SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// extends the lifetime of the original blob, and sets the lifetimes of + /// the resulting chunks (or extends the lifetimes of already-existing + /// chunks). + /// * Touching a chunk extends its lifetime, but the server MAY choose not + /// to extend the lifetime of the original blob. + /// * Touching the original blob extends its lifetime, but the server MAY + /// choose not to extend the lifetimes of chunks derived from it. + /// + /// When blob splitting and splicing is used at the same time, the clients and + /// the server SHOULD agree out-of-band upon a chunking algorithm used by both + /// parties to benefit from each other's chunk data and avoid unnecessary data + /// duplication. + /// + /// Errors: + /// + /// * `NOT_FOUND`: The requested blob is not present in the CAS, OR there is no + /// split information available for the blob, OR at least one chunk needed to + /// reconstruct the blob is missing from the CAS. + /// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the blob + /// chunks. + async fn split_blob( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// SpliceBlob tells the CAS how chunks can compose a blob. + /// + /// This is the complementary operation to the + /// [ContentAddressableStorage.SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// function to handle the chunked upload of large blobs to save upload + /// traffic. + /// + /// When uploading a large blob using chunked upload, clients MUST first upload + /// all chunks to the CAS, then call this RPC to tell the server how those chunks + /// compose the original blob. The chunks referenced in the SpliceBlob call SHOULD be + /// available in the CAS before calling this RPC. + /// + /// If a client needs to upload a large blob and is able to split a blob into + /// chunks in such a way that reusable chunks are obtained, e.g., by means of + /// content-defined chunking, it can first determine which parts of the blob + /// are already available in the remote CAS and upload the missing chunks, and + /// then use this API to store information on how the chunks compose the + /// original blob. + /// + /// Servers which implement this functionality MUST declare that they support + /// it by setting the + /// [CacheCapabilities.splice_blob_support][build.bazel.remote.execution.v2.CacheCapabilities.splice_blob_support] + /// field accordingly. + /// + /// Clients MUST check that the server supports this capability, before using + /// it. + /// + /// In order to ensure data consistency of the CAS, the server MUST only add + /// blobs to the CAS after verifying their digests. In particular, servers MUST NOT + /// trust digests provided by the client. The server MAY accept a request as no-op + /// if the client-specified blob is already in CAS or if information on how to + /// construct the blob from chunks is available. If the client-specified blob is + /// not already in the CAS, the server MUST verify that the digest of the newly + /// created blob assembled from chunks matches the digest specified by the + /// client, and reject the request if they differ. Servers MAY choose to allow + /// overwriting existing chunk mappings or to store multiple chunk mappings for + /// the same blob. + /// + /// When blob splitting and splicing is used at the same time, the clients and + /// the server SHOULD agree out-of-band upon a chunking algorithm used by both + /// parties to benefit from each other's chunk data and avoid unnecessary data + /// duplication. + /// + /// Errors: + /// + /// * `NOT_FOUND`: At least one of the blob chunks is not present in the CAS. + /// * `RESOURCE_EXHAUSTED`: There is insufficient disk quota to store the + /// spliced blob. + /// * `INVALID_ARGUMENT`: The digest of the spliced blob is different from the + /// provided expected digest. + /// * `ALREADY_EXISTS`: The blob already exists in CAS and the server did not + /// extend the lifetime of the chunks specified in the request, e.g. because + /// it prefers a different chunking and extended those instead. Clients can + /// call [SplitBlob][build.bazel.remote.execution.v2.ContentAddressableStorage.SplitBlob] + /// to check what chunk mapping the server is using. + async fn splice_blob( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } /// The CAS (content-addressable storage) is used to store the inputs to and /// outputs from the execution service. Each piece of content is addressed by the @@ -3843,7 +4287,7 @@ pub mod content_addressable_storage_server { let inner = self.inner.clone(); let fut = async move { let method = FindMissingBlobsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -3892,7 +4336,7 @@ pub mod content_addressable_storage_server { let inner = self.inner.clone(); let fut = async move { let method = BatchUpdateBlobsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -3941,7 +4385,7 @@ pub mod content_addressable_storage_server { let inner = self.inner.clone(); let fut = async move { let method = BatchReadBlobsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -3988,7 +4432,7 @@ pub mod content_addressable_storage_server { let inner = self.inner.clone(); let fut = async move { let method = GetTreeSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -4003,6 +4447,104 @@ pub mod content_addressable_storage_server { }; Box::pin(fut) } + "/build.bazel.remote.execution.v2.ContentAddressableStorage/SplitBlob" => { + #[allow(non_camel_case_types)] + struct SplitBlobSvc(pub Arc); + impl< + T: ContentAddressableStorage, + > tonic::server::UnaryService + for SplitBlobSvc { + type Response = super::SplitBlobResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::split_blob( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SplitBlobSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/build.bazel.remote.execution.v2.ContentAddressableStorage/SpliceBlob" => { + #[allow(non_camel_case_types)] + struct SpliceBlobSvc(pub Arc); + impl< + T: ContentAddressableStorage, + > tonic::server::UnaryService + for SpliceBlobSvc { + type Response = super::SpliceBlobResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::splice_blob( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SpliceBlobSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { let mut response = http::Response::new( @@ -4043,6 +4585,133 @@ pub mod content_addressable_storage_server { const NAME: &'static str = SERVICE_NAME; } } +/// Generated client implementations. +pub mod capabilities_client { + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + /// The Capabilities service may be used by remote execution clients to query + /// various server properties, in order to self-configure or return meaningful + /// error messages. + /// + /// The query may include a particular `instance_name`, in which case the values + /// returned will pertain to that instance. + #[derive(Debug, Clone)] + pub struct CapabilitiesClient { + inner: tonic::client::Grpc, + } + impl CapabilitiesClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> CapabilitiesClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, + { + CapabilitiesClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// GetCapabilities returns the server capabilities configuration of the + /// remote endpoint. + /// Only the capabilities of the services supported by the endpoint will + /// be returned: + /// * Execution + CAS + Action Cache endpoints should return both + /// CacheCapabilities and ExecutionCapabilities. + /// * Execution only endpoints should return ExecutionCapabilities. + /// * CAS + Action Cache only endpoints should return CacheCapabilities. + /// + /// There are no method-specific errors. + pub async fn get_capabilities( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/build.bazel.remote.execution.v2.Capabilities/GetCapabilities", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "build.bazel.remote.execution.v2.Capabilities", + "GetCapabilities", + ), + ); + self.inner.unary(req, path, codec).await + } + } +} /// Generated server implementations. pub mod capabilities_server { #![allow( @@ -4186,7 +4855,7 @@ pub mod capabilities_server { let inner = self.inner.clone(); let fut = async move { let method = GetCapabilitiesSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, diff --git a/nativelink-proto/genproto/build.bazel.semver.pb.rs b/nativelink-proto/genproto/build.bazel.semver.pb.rs index 5cb0a9695..7cdd17fe8 100644 --- a/nativelink-proto/genproto/build.bazel.semver.pb.rs +++ b/nativelink-proto/genproto/build.bazel.semver.pb.rs @@ -14,7 +14,7 @@ // This file is @generated by prost-build. /// The full version of a given tool. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct SemVer { /// The major version, e.g 10 for 10.2.3. #[prost(int32, tag = "1")] diff --git a/nativelink-proto/genproto/build_event_stream.pb.rs b/nativelink-proto/genproto/build_event_stream.pb.rs index 4becc1cd5..279cf5da3 100644 --- a/nativelink-proto/genproto/build_event_stream.pb.rs +++ b/nativelink-proto/genproto/build_event_stream.pb.rs @@ -21,7 +21,7 @@ /// event has an id that is mentioned as child id in an earlier event and a build /// invocation is complete if and only if all direct and indirect children of the /// initial event have been posted. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildEventId { #[prost( oneof = "build_event_id::Id", @@ -34,14 +34,14 @@ pub mod build_event_id { /// Generic identifier for a build event. This is the default type of /// BuildEventId, but should not be used outside testing; nevertheless, /// tools should handle build events with this kind of id gracefully. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct UnknownBuildEventId { #[prost(string, tag = "1")] pub details: ::prost::alloc::string::String, } /// Identifier of an event reporting progress. Those events are also used to /// chain in events that come early. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ProgressId { /// Unique identifier. No assumption should be made about how the ids are /// assigned; the only meaningful operation on this field is test for @@ -51,14 +51,14 @@ pub mod build_event_id { } /// Identifier of an event indicating the beginning of a build; this will /// normally be the first event. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildStartedId {} /// Identifier on an event indicating the original commandline received by /// the bazel server. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct UnstructuredCommandLineId {} /// Identifier on an event describing the commandline received by Bazel. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StructuredCommandLineId { /// A title for this command line value, as there may be multiple. /// For example, a single invocation may wish to report both the literal and @@ -68,15 +68,15 @@ pub mod build_event_id { pub command_line_label: ::prost::alloc::string::String, } /// Identifier of an event indicating the workspace status. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct WorkspaceStatusId {} /// Identifier on an event reporting on the options included in the command /// line, both explicitly and implicitly. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct OptionsParsedId {} /// Identifier of an event reporting that an external resource was fetched /// from. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct FetchId { /// The external resource that was fetched from. #[prost(string, tag = "1")] @@ -88,18 +88,18 @@ pub mod build_event_id { /// have been skipped for some reason, if the actual expansion was still /// carried out (e.g., if keep_going is set). In this case, the /// pattern_skipped choice in the id field is to be made. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PatternExpandedId { #[prost(string, repeated, tag = "1")] pub pattern: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct WorkspaceConfigId {} - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildMetadataId {} /// Identifier of an event indicating that a target has been expanded by /// identifying for which configurations it should be build. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetConfiguredId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -120,7 +120,7 @@ pub mod build_event_id { } /// Identifier of an event introducing a named set of files (usually artifacts) /// to be referred to in later messages. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct NamedSetOfFilesId { /// Identifier of the file set; this is an opaque string valid only for the /// particular instance of the event stream. @@ -128,7 +128,7 @@ pub mod build_event_id { pub id: ::prost::alloc::string::String, } /// Identifier of an event introducing a configuration. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConfigurationId { /// Identifier of the configuration; users of the protocol should not make /// any assumptions about it having any structure, or equality of the @@ -141,7 +141,7 @@ pub mod build_event_id { } /// Identifier of an event indicating that a target was built completely; this /// does not include running the test if the target is a test target. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetCompletedId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -166,7 +166,7 @@ pub mod build_event_id { /// Identifier of an event reporting that an action was completed (not all /// actions are reported, only the ones that can be considered important; /// this includes all failed actions). - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionCompletedId { #[prost(string, tag = "1")] pub primary_output: ::prost::alloc::string::String, @@ -182,7 +182,7 @@ pub mod build_event_id { /// any case, it will report some form of error (i.e., the payload will be an /// Aborted event); there are no regular events using this identifier. The /// purpose of those events is to serve as the root cause of a failed target. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct UnconfiguredLabelId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -191,7 +191,7 @@ pub mod build_event_id { /// label, usually a visibility error. In any case, an event with such an /// id will always report some form of error (i.e., the payload will be an /// Aborted event); there are no regular events using this identifier. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConfiguredLabelId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -203,7 +203,7 @@ pub mod build_event_id { /// in such a way as to uniquely identify the action within a build. In fact, /// attempts for the same test, run, shard triple are counted sequentially, /// starting with 1. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestResultId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -217,7 +217,7 @@ pub mod build_event_id { pub attempt: i32, } /// Identifier of an event reporting progress of an individual test run. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestProgressId { /// The label of the target for the action. #[prost(string, tag = "1")] @@ -241,7 +241,7 @@ pub mod build_event_id { pub opaque_count: i32, } /// Identifier of an event reporting the summary of a test. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestSummaryId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -249,7 +249,7 @@ pub mod build_event_id { pub configuration: ::core::option::Option, } /// Identifier of an event reporting the summary of a target. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetSummaryId { #[prost(string, tag = "1")] pub label: ::prost::alloc::string::String, @@ -257,23 +257,23 @@ pub mod build_event_id { pub configuration: ::core::option::Option, } /// Identifier of the BuildFinished event, indicating the end of a build. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildFinishedId {} /// Identifier of an event providing additional logs/statistics after /// completion of the build. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildToolLogsId {} /// Identifier of an event providing build metrics after completion /// of the build. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildMetricsId {} /// Identifier of an event providing convenience symlinks information. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConvenienceSymlinksIdentifiedId {} /// Identifier of an event providing the ExecRequest of a run command. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExecRequestId {} - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum Id { #[prost(message, tag = "1")] Unknown(UnknownBuildEventId), @@ -336,7 +336,7 @@ pub mod build_event_id { /// Payload of an event summarizing the progress of the build so far. Those /// events are also used to be parents of events where the more logical parent /// event cannot be posted yet as the needed information is not yet complete. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Progress { /// The next chunk of stdout that bazel produced since the last progress event /// or the beginning of the build. @@ -355,7 +355,7 @@ pub struct Progress { } /// Payload of an event indicating that an expected event will not come, as /// the build is aborted prematurely for some reason. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Aborted { #[prost(enumeration = "aborted::AbortReason", tag = "1")] pub reason: i32, @@ -452,7 +452,7 @@ pub mod aborted { /// to be build is contained in one of the announced child events; it is an /// invariant that precisely one of the announced child events has a non-empty /// target pattern. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildStarted { #[prost(string, tag = "1")] pub uuid: ::prost::alloc::string::String, @@ -487,7 +487,7 @@ pub struct BuildStarted { pub server_pid: i64, } /// Configuration related to the blaze workspace and output tree. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct WorkspaceConfig { /// The root of the local blaze exec root. All output files live underneath /// this at "blaze-out/". @@ -500,7 +500,7 @@ pub struct WorkspaceConfig { /// like name and relevant entries of rc-files and client environment variables. /// However, it does contain enough information to reproduce the build /// invocation. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct UnstructuredCommandLine { #[prost(string, repeated, tag = "1")] pub args: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, @@ -528,7 +528,7 @@ pub struct OptionsParsed { /// Payload of an event indicating that an external resource was fetched. This /// event will only occur in streams where an actual fetch happened, not in ones /// where a cached copy of the entity to be fetched was used. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Fetch { #[prost(bool, tag = "1")] pub success: bool, @@ -544,7 +544,7 @@ pub struct WorkspaceStatus { } /// Nested message and enum types in `WorkspaceStatus`. pub mod workspace_status { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Item { #[prost(string, tag = "1")] pub key: ::prost::alloc::string::String, @@ -599,7 +599,7 @@ pub mod pattern_expanded { /// Represents a test_suite target and the tests that it expanded to. Nested /// test suites are recursively expanded. The test labels only contain the /// final test targets, not any nested suites. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestSuiteExpansion { /// The label of the test_suite rule. #[prost(string, tag = "1")] @@ -615,7 +615,7 @@ pub mod pattern_expanded { /// been identified. As with pattern expansion the main information is in the /// chaining part: the id will contain the target that was configured and the /// children id will contain the configured targets it was configured to. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetConfigured { /// The kind of target (e.g., e.g. "cc_library rule", "source file", /// "generated file") where the completion is reported. @@ -629,7 +629,7 @@ pub struct TargetConfigured { #[prost(string, repeated, tag = "3")] pub tag: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct File { /// A sequence of prefixes to apply to the file name to construct a full path. /// In most but not all cases, there will be 3 entries: @@ -653,7 +653,7 @@ pub struct File { } /// Nested message and enum types in `File`. pub mod file { - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum File { /// A location where the contents of the file can be found. The string is /// encoded according to RFC2396. @@ -907,7 +907,7 @@ pub mod test_result { #[prost(message, optional, tag = "4")] pub time: ::core::option::Option<::prost_types::Duration>, } - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ResourceUsage { #[prost(string, tag = "1")] pub name: ::prost::alloc::string::String, @@ -917,7 +917,7 @@ pub mod test_result { } } /// Event payload providing information about an active, individual test run. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestProgress { /// Identifies a resource that may provide information about an active test /// run. The resource is not necessarily a file and may need to be queried @@ -993,7 +993,7 @@ pub struct TestSummary { pub total_run_duration: ::core::option::Option<::prost_types::Duration>, } /// Payload of the event summarizing a target (test or non-test). -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetSummary { /// Conjunction of TargetComplete events for this target, including aspects. #[prost(bool, tag = "1")] @@ -1039,7 +1039,7 @@ pub mod build_finished { /// rarely do) and are not part of the public API. /// /// A build was successful iff ExitCode.code equals 0. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExitCode { /// The name of the exit code. #[prost(string, tag = "1")] @@ -1049,7 +1049,7 @@ pub mod build_finished { pub code: i32, } /// Things that happened during the build that could be of interest. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct AnomalyReport { /// Was the build suspended at any time during the build. /// Examples of suspensions are SIGSTOP, or the hardware being put to sleep. @@ -1128,7 +1128,7 @@ pub mod build_metrics { } /// Nested message and enum types in `ActionSummary`. pub mod action_summary { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionData { #[prost(string, tag = "1")] pub mnemonic: ::prost::alloc::string::String, @@ -1154,7 +1154,7 @@ pub mod build_metrics { #[prost(int64, tag = "7")] pub actions_created: i64, } - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct RunnerCount { #[prost(string, tag = "1")] pub name: ::prost::alloc::string::String, @@ -1183,7 +1183,7 @@ pub mod build_metrics { } /// Nested message and enum types in `MemoryMetrics`. pub mod memory_metrics { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GarbageMetrics { /// Type of garbage collected, e.g. G1 Old Gen. #[prost(string, tag = "1")] @@ -1194,7 +1194,7 @@ pub mod build_metrics { pub garbage_collected: i64, } } - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetMetrics { /// DEPRECATED /// No longer populated. It never measured what it was supposed to (targets @@ -1238,7 +1238,7 @@ pub mod build_metrics { super::super::devtools::build::lib::packages::metrics::PackageLoadMetrics, >, } - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TimingMetrics { /// For Skymeld, it's possible that /// analysis_phase_time_in_ms + execution_phase_time_in_ms >= wall_time_in_ms @@ -1265,7 +1265,7 @@ pub mod build_metrics { #[prost(int64, tag = "5")] pub actions_execution_start_in_ms: i64, } - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CumulativeMetrics { /// One-indexed number of "analyses" the server has run, including the /// current one. Will be incremented for every build/test/cquery/etc. command @@ -1278,7 +1278,7 @@ pub mod build_metrics { #[prost(int32, tag = "12")] pub num_builds: i32, } - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ArtifactMetrics { /// Measures all source files newly read this build. Does not include /// unchanged sources on incremental builds. @@ -1305,7 +1305,7 @@ pub mod build_metrics { } /// Nested message and enum types in `ArtifactMetrics`. pub mod artifact_metrics { - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct FilesMetric { #[prost(int64, tag = "1")] pub size_in_bytes: i64, @@ -1314,7 +1314,7 @@ pub mod build_metrics { } } /// Data about the evaluation of Skyfunctions. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct EvaluationStat { /// Name of the Skyfunction. #[prost(string, tag = "1")] @@ -1405,7 +1405,7 @@ pub mod build_metrics { /// For SkyKeys in 'done values' where the SkyValue is of type /// RuleConfiguredTargetValue, we pull those out separately and report the /// ruleClass and action count. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct RuleClassCount { /// Unique key for the rule class. #[prost(string, tag = "1")] @@ -1421,7 +1421,7 @@ pub mod build_metrics { pub action_count: u64, } /// For SkyKeys whose function name is ASPECT break out that information - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct AspectCount { /// Unique key for Aspect. #[prost(string, tag = "1")] @@ -1486,7 +1486,7 @@ pub mod build_metrics { /// Nested message and enum types in `WorkerMetrics`. pub mod worker_metrics { /// Information collected from worker at some point. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct WorkerStats { /// Epoch unix time of collection of metrics. #[prost(int64, tag = "1")] @@ -1570,7 +1570,7 @@ pub mod build_metrics { } } /// Information about host network. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct NetworkMetrics { #[prost(message, optional, tag = "1")] pub system_network_stats: ::core::option::Option< @@ -1581,7 +1581,7 @@ pub mod build_metrics { pub mod network_metrics { /// Information for all the network traffic going on on the host machine /// during the invocation. - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct SystemNetworkStats { /// Total bytes sent during the invocation. #[prost(uint64, tag = "1")] @@ -1621,7 +1621,7 @@ pub mod build_metrics { } /// Nested message and enum types in `WorkerPoolMetrics`. pub mod worker_pool_metrics { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct WorkerPoolStats { /// Hash of worker pool these stats are for. Contains information about /// startup flags. @@ -1669,7 +1669,7 @@ pub mod build_metrics { } /// Nested message and enum types in `DynamicExecutionMetrics`. pub mod dynamic_execution_metrics { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct RaceStatistics { /// Mnemonic of the action. #[prost(string, tag = "1")] @@ -1708,7 +1708,7 @@ pub struct ConvenienceSymlinksIdentified { } /// The message that contains what type of action to perform on a given path and /// target of a symlink. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConvenienceSymlink { /// The path of the symlink to be created or deleted, absolute or relative to /// the workspace, creating any directories necessary. If a symlink already @@ -1787,7 +1787,7 @@ pub struct ExecRequestConstructed { pub should_exec: bool, } /// An environment variable provided by a run command after a successful build. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct EnvironmentVariable { #[prost(bytes = "bytes", tag = "1")] pub name: ::prost::bytes::Bytes, diff --git a/nativelink-proto/genproto/com.github.trace_machina.nativelink.events.pb.rs b/nativelink-proto/genproto/com.github.trace_machina.nativelink.events.pb.rs index f433da4fa..30d2d9bb4 100644 --- a/nativelink-proto/genproto/com.github.trace_machina.nativelink.events.pb.rs +++ b/nativelink-proto/genproto/com.github.trace_machina.nativelink.events.pb.rs @@ -29,7 +29,7 @@ pub struct BatchUpdateBlobsRequestOverride { } /// Nested message and enum types in `BatchUpdateBlobsRequestOverride`. pub mod batch_update_blobs_request_override { - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Request { #[prost(message, optional, tag = "1")] pub digest: ::core::option::Option< @@ -82,7 +82,7 @@ pub mod batch_read_blobs_response_override { } /// / Same as google.bytestream.WriteRequest, but without the data field, /// / and add a `data_len` field. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct WriteRequestOverride { #[prost(string, tag = "1")] pub resource_name: ::prost::alloc::string::String, @@ -299,7 +299,7 @@ pub struct OriginEvents { pub events: ::prost::alloc::vec::Vec, } /// / Bep event that has occurred. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BepEvent { /// / The version of this message. #[prost(uint32, tag = "1")] @@ -316,7 +316,7 @@ pub struct BepEvent { /// Nested message and enum types in `BepEvent`. pub mod bep_event { /// / The event that occurred. - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum Event { #[prost(message, tag = "3")] LifecycleEvent( diff --git a/nativelink-proto/genproto/com.github.trace_machina.nativelink.remote_execution.pb.rs b/nativelink-proto/genproto/com.github.trace_machina.nativelink.remote_execution.pb.rs index e5295d0a8..3116d1b57 100644 --- a/nativelink-proto/genproto/com.github.trace_machina.nativelink.remote_execution.pb.rs +++ b/nativelink-proto/genproto/com.github.trace_machina.nativelink.remote_execution.pb.rs @@ -14,10 +14,10 @@ // This file is @generated by prost-build. /// / Request object for keep alive requests. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct KeepAliveRequest {} /// / Request object for going away requests. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct GoingAwayRequest {} /// / Represents the initial request sent to the scheduler informing the /// / scheduler about this worker's capabilities and metadata. @@ -83,14 +83,14 @@ pub mod execute_result { } } /// / The result of an ExecutionComplete. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExecuteComplete { /// / The operation ID that was executed. #[prost(string, tag = "1")] pub operation_id: ::prost::alloc::string::String, } /// / Resource usage observed by the worker while running one action. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionResourceUsage { /// / Peak resident memory observed for the action process tree. #[prost(uint64, tag = "1")] @@ -104,16 +104,21 @@ pub struct ActionResourceUsage { /// / The worker ID that observed the resource usage. #[prost(string, tag = "4")] pub worker_id: ::prost::alloc::string::String, + /// / Total CPU time consumed by the action process tree, in milliseconds. + /// / User and system time combined, summed across every process in the + /// / action's process group. + #[prost(uint64, tag = "5")] + pub cpu_time_ms: u64, } /// / Result sent back from the server when a node connects. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConnectionResult { /// / The worker ID to place in the action results generated by this worker. #[prost(string, tag = "1")] pub worker_id: ::prost::alloc::string::String, } /// / Request to kill a running operation sent from the scheduler to a worker. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct KillOperationRequest { /// / The the operation id for the operation to be killed. #[prost(string, tag = "1")] @@ -347,7 +352,7 @@ pub mod worker_api_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/com.github.trace_machina.nativelink.remote_execution.WorkerApi/ConnectWorker", ); @@ -515,7 +520,7 @@ pub mod worker_api_server { let inner = self.inner.clone(); let fut = async move { let method = ConnectWorkerSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, diff --git a/nativelink-proto/genproto/command_line.pb.rs b/nativelink-proto/genproto/command_line.pb.rs index cea8bfc8a..7cc467eb2 100644 --- a/nativelink-proto/genproto/command_line.pb.rs +++ b/nativelink-proto/genproto/command_line.pb.rs @@ -54,7 +54,7 @@ pub mod command_line_section { } } /// Wrapper to allow a list of strings in the "oneof" section_type. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ChunkList { #[prost(string, repeated, tag = "1")] pub chunk: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, @@ -74,7 +74,7 @@ pub struct OptionList { /// represents the canonical form of the command line, with the values as Bazel /// understands them, then the expansion flag, which has no value, would not /// appear, and the flags it expands to would. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Option { /// How the option looks with the option and its value combined. Depending on /// the purpose of this command line report, this could be the canonical diff --git a/nativelink-proto/genproto/devtools.build.lib.packages.metrics.pb.rs b/nativelink-proto/genproto/devtools.build.lib.packages.metrics.pb.rs index f82bdb84f..43a8979be 100644 --- a/nativelink-proto/genproto/devtools.build.lib.packages.metrics.pb.rs +++ b/nativelink-proto/genproto/devtools.build.lib.packages.metrics.pb.rs @@ -14,7 +14,7 @@ // This file is @generated by prost-build. /// Message used to concisely report all package metrics. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PackageLoadMetrics { /// Name of the package. #[prost(string, optional, tag = "1")] diff --git a/nativelink-proto/genproto/failure_details.pb.rs b/nativelink-proto/genproto/failure_details.pb.rs index f890f9d85..1c7192545 100644 --- a/nativelink-proto/genproto/failure_details.pb.rs +++ b/nativelink-proto/genproto/failure_details.pb.rs @@ -13,7 +13,7 @@ // limitations under the License. // This file is @generated by prost-build. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct FailureDetailMetadata { #[prost(uint32, tag = "1")] pub exit_code: u32, @@ -209,7 +209,7 @@ pub mod failure_detail { RemoteAnalysisCaching(super::RemoteAnalysisCaching), } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Interrupted { #[prost(enumeration = "interrupted::Code", tag = "1")] pub code: i32, @@ -307,7 +307,7 @@ pub mod interrupted { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Spawn { #[prost(enumeration = "spawn::Code", tag = "1")] pub code: i32, @@ -424,7 +424,7 @@ pub mod spawn { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExternalRepository { /// Additional data could include external repository names. #[prost(enumeration = "external_repository::Code", tag = "1")] @@ -486,7 +486,7 @@ pub mod external_repository { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildProgress { /// Additional data could include the build progress upload endpoint. #[prost(enumeration = "build_progress::Code", tag = "1")] @@ -598,7 +598,7 @@ pub mod build_progress { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct RemoteOptions { #[prost(enumeration = "remote_options::Code", tag = "1")] pub code: i32, @@ -660,7 +660,7 @@ pub mod remote_options { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ClientEnvironment { #[prost(enumeration = "client_environment::Code", tag = "1")] pub code: i32, @@ -757,7 +757,7 @@ pub mod crash { } } } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Throwable { /// The class name of the java.lang.Throwable. #[prost(string, tag = "1")] @@ -771,7 +771,7 @@ pub struct Throwable { #[prost(string, repeated, tag = "3")] pub stack_trace: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct SymlinkForest { #[prost(enumeration = "symlink_forest::Code", tag = "1")] pub code: i32, @@ -827,7 +827,7 @@ pub mod symlink_forest { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildReport { /// Additional data for partial failures might include the build report that /// failed to be written. @@ -881,7 +881,7 @@ pub mod build_report { } } /// Failure details for errors produced when using Skyfocus -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Skyfocus { #[prost(enumeration = "skyfocus::Code", tag = "1")] pub code: i32, @@ -940,7 +940,7 @@ pub mod skyfocus { } } /// Failure details for errors produced during remote analysis caching. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct RemoteAnalysisCaching { #[prost(enumeration = "remote_analysis_caching::Code", tag = "1")] pub code: i32, @@ -993,7 +993,7 @@ pub mod remote_analysis_caching { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct PackageOptions { #[prost(enumeration = "package_options::Code", tag = "1")] pub code: i32, @@ -1040,7 +1040,7 @@ pub mod package_options { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct RemoteExecution { #[prost(enumeration = "remote_execution::Code", tag = "1")] pub code: i32, @@ -1166,7 +1166,7 @@ pub mod remote_execution { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Execution { #[prost(enumeration = "execution::Code", tag = "1")] pub code: i32, @@ -1403,7 +1403,7 @@ pub mod execution { } } /// Failure details about Bazel's WORKSPACE features. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Workspaces { #[prost(enumeration = "workspaces::Code", tag = "1")] pub code: i32, @@ -1470,7 +1470,7 @@ pub mod workspaces { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CrashOptions { #[prost(enumeration = "crash_options::Code", tag = "1")] pub code: i32, @@ -1511,7 +1511,7 @@ pub mod crash_options { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Filesystem { #[prost(enumeration = "filesystem::Code", tag = "1")] pub code: i32, @@ -1577,7 +1577,7 @@ pub mod filesystem { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExecutionOptions { #[prost(enumeration = "execution_options::Code", tag = "1")] pub code: i32, @@ -1671,7 +1671,7 @@ pub mod execution_options { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Command { #[prost(enumeration = "command::Code", tag = "1")] pub code: i32, @@ -1770,7 +1770,7 @@ pub mod command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct GrpcServer { #[prost(enumeration = "grpc_server::Code", tag = "1")] pub code: i32, @@ -1823,7 +1823,7 @@ pub mod grpc_server { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CanonicalizeFlags { #[prost(enumeration = "canonicalize_flags::Code", tag = "1")] pub code: i32, @@ -1872,7 +1872,7 @@ pub mod canonicalize_flags { /// intended as a grab-bag for all Bazel flag value constraint violations, which /// instead generally belong in the category for the subsystem whose flag values /// participate in the constraint. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildConfiguration { #[prost(enumeration = "build_configuration::Code", tag = "1")] pub code: i32, @@ -1983,7 +1983,7 @@ pub mod build_configuration { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct InfoCommand { #[prost(enumeration = "info_command::Code", tag = "1")] pub code: i32, @@ -2039,7 +2039,7 @@ pub mod info_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct MemoryOptions { #[prost(enumeration = "memory_options::Code", tag = "1")] pub code: i32, @@ -2061,8 +2061,10 @@ pub mod memory_options { pub enum Code { MemoryOptionsUnknown = 0, /// Deprecated: validation is now implemented by the option converter. + #[deprecated] DeprecatedExperimentalOomMoreEagerlyThresholdInvalidValue = 1, /// Deprecated: no tenured collectors found is now a crash on startup. + #[deprecated] DeprecatedExperimentalOomMoreEagerlyNoTenuredCollectorsFound = 2, } impl Code { @@ -2073,9 +2075,11 @@ pub mod memory_options { pub fn as_str_name(&self) -> &'static str { match self { Self::MemoryOptionsUnknown => "MEMORY_OPTIONS_UNKNOWN", + #[allow(deprecated)] Self::DeprecatedExperimentalOomMoreEagerlyThresholdInvalidValue => { "DEPRECATED_EXPERIMENTAL_OOM_MORE_EAGERLY_THRESHOLD_INVALID_VALUE" } + #[allow(deprecated)] Self::DeprecatedExperimentalOomMoreEagerlyNoTenuredCollectorsFound => { "DEPRECATED_EXPERIMENTAL_OOM_MORE_EAGERLY_NO_TENURED_COLLECTORS_FOUND" } @@ -2086,10 +2090,14 @@ pub mod memory_options { match value { "MEMORY_OPTIONS_UNKNOWN" => Some(Self::MemoryOptionsUnknown), "DEPRECATED_EXPERIMENTAL_OOM_MORE_EAGERLY_THRESHOLD_INVALID_VALUE" => { - Some(Self::DeprecatedExperimentalOomMoreEagerlyThresholdInvalidValue) + Some( + #[allow(deprecated)] + Self::DeprecatedExperimentalOomMoreEagerlyThresholdInvalidValue, + ) } "DEPRECATED_EXPERIMENTAL_OOM_MORE_EAGERLY_NO_TENURED_COLLECTORS_FOUND" => { Some( + #[allow(deprecated)] Self::DeprecatedExperimentalOomMoreEagerlyNoTenuredCollectorsFound, ) } @@ -2098,7 +2106,7 @@ pub mod memory_options { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Query { #[prost(enumeration = "query::Code", tag = "1")] pub code: i32, @@ -2294,7 +2302,7 @@ pub mod query { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct LocalExecution { #[prost(enumeration = "local_execution::Code", tag = "1")] pub code: i32, @@ -2341,7 +2349,7 @@ pub mod local_execution { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionCache { #[prost(enumeration = "action_cache::Code", tag = "1")] pub code: i32, @@ -2385,7 +2393,7 @@ pub mod action_cache { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct FetchCommand { #[prost(enumeration = "fetch_command::Code", tag = "1")] pub code: i32, @@ -2438,7 +2446,7 @@ pub mod fetch_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct SyncCommand { #[prost(enumeration = "sync_command::Code", tag = "1")] pub code: i32, @@ -2491,7 +2499,7 @@ pub mod sync_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Sandbox { #[prost(enumeration = "sandbox::Code", tag = "1")] pub code: i32, @@ -2577,7 +2585,7 @@ pub mod sandbox { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct IncludeScanning { #[prost(enumeration = "include_scanning::Code", tag = "1")] pub code: i32, @@ -2657,7 +2665,7 @@ pub mod include_scanning { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestCommand { #[prost(enumeration = "test_command::Code", tag = "1")] pub code: i32, @@ -2707,7 +2715,7 @@ pub mod test_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionQuery { #[prost(enumeration = "action_query::Code", tag = "1")] pub code: i32, @@ -2815,7 +2823,7 @@ pub mod action_query { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TargetPatterns { #[prost(enumeration = "target_patterns::Code", tag = "1")] pub code: i32, @@ -2937,7 +2945,7 @@ pub mod target_patterns { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CleanCommand { #[prost(enumeration = "clean_command::Code", tag = "1")] pub code: i32, @@ -3010,7 +3018,7 @@ pub mod clean_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConfigCommand { #[prost(enumeration = "config_command::Code", tag = "1")] pub code: i32, @@ -3057,7 +3065,7 @@ pub mod config_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConfigurableQuery { #[prost(enumeration = "configurable_query::Code", tag = "1")] pub code: i32, @@ -3147,7 +3155,7 @@ pub mod configurable_query { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DumpCommand { #[prost(enumeration = "dump_command::Code", tag = "1")] pub code: i32, @@ -3208,7 +3216,7 @@ pub mod dump_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct HelpCommand { #[prost(enumeration = "help_command::Code", tag = "1")] pub code: i32, @@ -3255,7 +3263,7 @@ pub mod help_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct MobileInstall { #[prost(enumeration = "mobile_install::Code", tag = "1")] pub code: i32, @@ -3314,7 +3322,7 @@ pub mod mobile_install { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ProfileCommand { #[prost(enumeration = "profile_command::Code", tag = "1")] pub code: i32, @@ -3361,7 +3369,7 @@ pub mod profile_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct RunCommand { #[prost(enumeration = "run_command::Code", tag = "1")] pub code: i32, @@ -3471,7 +3479,7 @@ pub mod run_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct VersionCommand { #[prost(enumeration = "version_command::Code", tag = "1")] pub code: i32, @@ -3515,7 +3523,7 @@ pub mod version_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct PrintActionCommand { #[prost(enumeration = "print_action_command::Code", tag = "1")] pub code: i32, @@ -3570,7 +3578,7 @@ pub mod print_action_command { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct WorkspaceStatus { #[prost(enumeration = "workspace_status::Code", tag = "1")] pub code: i32, @@ -3632,7 +3640,7 @@ pub mod workspace_status { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct JavaCompile { #[prost(enumeration = "java_compile::Code", tag = "1")] pub code: i32, @@ -3691,7 +3699,7 @@ pub mod java_compile { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ActionRewinding { #[prost(enumeration = "action_rewinding::Code", tag = "1")] pub code: i32, @@ -3718,6 +3726,7 @@ pub mod action_rewinding { LostInputRewindingDisabled = 5, LostOutputRewindingDisabled = 6, /// Deprecated: attempting to rewind a source artifact is now a hard crash. + #[deprecated] DeprecatedLostInputIsSource = 2, } impl Code { @@ -3733,6 +3742,7 @@ pub mod action_rewinding { Self::LostOutputTooManyTimes => "LOST_OUTPUT_TOO_MANY_TIMES", Self::LostInputRewindingDisabled => "LOST_INPUT_REWINDING_DISABLED", Self::LostOutputRewindingDisabled => "LOST_OUTPUT_REWINDING_DISABLED", + #[allow(deprecated)] Self::DeprecatedLostInputIsSource => "DEPRECATED_LOST_INPUT_IS_SOURCE", } } @@ -3750,14 +3760,14 @@ pub mod action_rewinding { Some(Self::LostOutputRewindingDisabled) } "DEPRECATED_LOST_INPUT_IS_SOURCE" => { - Some(Self::DeprecatedLostInputIsSource) + Some(#[allow(deprecated)] Self::DeprecatedLostInputIsSource) } _ => None, } } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CppCompile { #[prost(enumeration = "cpp_compile::Code", tag = "1")] pub code: i32, @@ -3839,7 +3849,7 @@ pub mod cpp_compile { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct StarlarkAction { #[prost(enumeration = "starlark_action::Code", tag = "1")] pub code: i32, @@ -3890,7 +3900,7 @@ pub mod starlark_action { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct NinjaAction { #[prost(enumeration = "ninja_action::Code", tag = "1")] pub code: i32, @@ -3941,7 +3951,7 @@ pub mod ninja_action { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DynamicExecution { #[prost(enumeration = "dynamic_execution::Code", tag = "1")] pub code: i32, @@ -3994,7 +4004,7 @@ pub mod dynamic_execution { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct FailAction { #[prost(enumeration = "fail_action::Code", tag = "1")] pub code: i32, @@ -4061,7 +4071,7 @@ pub mod fail_action { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct SymlinkAction { #[prost(enumeration = "symlink_action::Code", tag = "1")] pub code: i32, @@ -4124,7 +4134,7 @@ pub mod symlink_action { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct CppLink { #[prost(enumeration = "cpp_link::Code", tag = "1")] pub code: i32, @@ -4173,7 +4183,7 @@ pub mod cpp_link { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct LtoAction { #[prost(enumeration = "lto_action::Code", tag = "1")] pub code: i32, @@ -4225,7 +4235,7 @@ pub mod lto_action { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct TestAction { #[prost(enumeration = "test_action::Code", tag = "1")] pub code: i32, @@ -4283,7 +4293,7 @@ pub mod test_action { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Worker { #[prost(enumeration = "worker::Code", tag = "1")] pub code: i32, @@ -4371,7 +4381,7 @@ pub mod worker { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Analysis { #[prost(enumeration = "analysis::Code", tag = "1")] pub code: i32, @@ -4493,7 +4503,7 @@ pub mod analysis { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct PackageLoading { #[prost(enumeration = "package_loading::Code", tag = "1")] pub code: i32, @@ -4654,7 +4664,7 @@ pub mod package_loading { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct Toolchain { #[prost(enumeration = "toolchain::Code", tag = "1")] pub code: i32, @@ -4718,7 +4728,7 @@ pub mod toolchain { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct StarlarkLoading { #[prost(enumeration = "starlark_loading::Code", tag = "1")] pub code: i32, @@ -4791,7 +4801,7 @@ pub mod starlark_loading { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ExternalDeps { #[prost(enumeration = "external_deps::Code", tag = "1")] pub code: i32, @@ -4853,7 +4863,7 @@ pub mod external_deps { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct DiffAwareness { #[prost(enumeration = "diff_awareness::Code", tag = "1")] pub code: i32, @@ -4897,7 +4907,7 @@ pub mod diff_awareness { } } } -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct ModCommand { #[prost(enumeration = "mod_command::Code", tag = "1")] pub code: i32, diff --git a/nativelink-proto/genproto/google.api.pb.rs b/nativelink-proto/genproto/google.api.pb.rs index 280cb2dc9..2895fd42d 100644 --- a/nativelink-proto/genproto/google.api.pb.rs +++ b/nativelink-proto/genproto/google.api.pb.rs @@ -353,7 +353,7 @@ pub mod http_rule { /// Determines the URL pattern is matched by this rules. This pattern can be /// used with any of the {get|put|post|delete|patch} methods. A custom method /// can be defined using the 'custom' field. - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum Pattern { /// Maps to HTTP GET. Used for listing and getting information about /// resources. @@ -380,7 +380,7 @@ pub mod http_rule { } } /// A custom pattern is used for defining custom HTTP verb. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct CustomHttpPattern { /// The name of this custom HTTP verb. #[prost(string, tag = "1")] diff --git a/nativelink-proto/genproto/google.bytestream.pb.rs b/nativelink-proto/genproto/google.bytestream.pb.rs index d0229a041..f6fc14a0e 100644 --- a/nativelink-proto/genproto/google.bytestream.pb.rs +++ b/nativelink-proto/genproto/google.bytestream.pb.rs @@ -14,7 +14,7 @@ // This file is @generated by prost-build. /// Request object for ByteStream.Read. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ReadRequest { /// The name of the resource to read. #[prost(string, tag = "1")] @@ -38,7 +38,7 @@ pub struct ReadRequest { } /// Response object for ByteStream.Read. #[derive(::derive_more::Debug)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] #[prost(skip_debug)] pub struct ReadResponse { /// A portion of the data for the resource. The service **may** leave `data` @@ -51,7 +51,7 @@ pub struct ReadResponse { } /// Request object for ByteStream.Write. #[derive(::derive_more::Debug)] -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] #[prost(skip_debug)] pub struct WriteRequest { /// The name of the resource to write. This **must** be set on the first @@ -87,21 +87,21 @@ pub struct WriteRequest { pub data: ::prost::bytes::Bytes, } /// Response object for ByteStream.Write. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct WriteResponse { /// The number of bytes that have been processed for the given resource. #[prost(int64, tag = "1")] pub committed_size: i64, } /// Request object for ByteStream.QueryWriteStatus. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct QueryWriteStatusRequest { /// The name of the resource whose write status is being requested. #[prost(string, tag = "1")] pub resource_name: ::prost::alloc::string::String, } /// Response object for ByteStream.QueryWriteStatus. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct QueryWriteStatusResponse { /// The number of bytes that have been processed for the given resource. #[prost(int64, tag = "1")] @@ -232,7 +232,7 @@ pub mod byte_stream_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.bytestream.ByteStream/Read", ); @@ -275,7 +275,7 @@ pub mod byte_stream_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.bytestream.ByteStream/Write", ); @@ -313,7 +313,7 @@ pub mod byte_stream_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.bytestream.ByteStream/QueryWriteStatus", ); @@ -530,7 +530,7 @@ pub mod byte_stream_server { let inner = self.inner.clone(); let fut = async move { let method = ReadSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -577,7 +577,7 @@ pub mod byte_stream_server { let inner = self.inner.clone(); let fut = async move { let method = WriteSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -622,7 +622,7 @@ pub mod byte_stream_server { let inner = self.inner.clone(); let fut = async move { let method = QueryWriteStatusSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, diff --git a/nativelink-proto/genproto/google.devtools.build.v1.pb.rs b/nativelink-proto/genproto/google.devtools.build.v1.pb.rs index 94d70d8f6..4f6918647 100644 --- a/nativelink-proto/genproto/google.devtools.build.v1.pb.rs +++ b/nativelink-proto/genproto/google.devtools.build.v1.pb.rs @@ -14,7 +14,7 @@ // This file is @generated by prost-build. /// Status used for both invocation attempt and overall build completion. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildStatus { /// The end result. #[prost(enumeration = "build_status::Result", tag = "1")] @@ -106,7 +106,7 @@ pub mod build_status { } /// An event representing some state change that occurred in the build. This /// message does not include field for uniquely identifying an event. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildEvent { /// This should be precisely the time when this event happened, and not when /// the event proto was created or sent. @@ -121,7 +121,7 @@ pub struct BuildEvent { /// Nested message and enum types in `BuildEvent`. pub mod build_event { /// Notification that the build system has attempted to run the build tool. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct InvocationAttemptStarted { /// The number of the invocation attempt, starting at 1 and increasing by 1 /// for each new attempt. Can be used to determine if there is a later @@ -133,7 +133,7 @@ pub mod build_event { pub details: ::core::option::Option<::prost_types::Any>, } /// Notification that an invocation attempt has finished. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct InvocationAttemptFinished { /// Final status of the invocation. #[prost(message, optional, tag = "3")] @@ -143,7 +143,7 @@ pub mod build_event { pub details: ::core::option::Option<::prost_types::Any>, } /// Notification that the build request is enqueued. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildEnqueued { /// Additional details about the Build. #[prost(message, optional, tag = "1")] @@ -152,7 +152,7 @@ pub mod build_event { /// Notification that the build request has finished, and no further /// invocations will occur. Note that this applies to the entire Build. /// Individual invocations trigger InvocationFinished when they finish. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildFinished { /// Final status of the build. #[prost(message, optional, tag = "1")] @@ -162,7 +162,7 @@ pub mod build_event { pub details: ::core::option::Option<::prost_types::Any>, } /// Textual output written to standard output or standard error. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ConsoleOutput { /// The output stream type. #[prost(enumeration = "super::ConsoleOutputStream", tag = "1")] @@ -174,7 +174,7 @@ pub mod build_event { /// Nested message and enum types in `ConsoleOutput`. pub mod console_output { /// The output stream content. - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum Output { /// Regular UTF-8 output; normal text. #[prost(string, tag = "2")] @@ -186,7 +186,7 @@ pub mod build_event { } /// Notification of the end of a build event stream published by a build /// component other than CONTROLLER (See StreamId.BuildComponents). - #[derive(Clone, Copy, PartialEq, ::prost::Message)] + #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct BuildComponentStreamFinished { /// How the event stream finished. #[prost(enumeration = "build_component_stream_finished::FinishType", tag = "1")] @@ -244,7 +244,7 @@ pub mod build_event { /// ////////////////////////////////////////////////////////////////////////// /// Events that indicate a state change of a build request in the build /// queue. - #[derive(Clone, PartialEq, ::prost::Oneof)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Oneof)] pub enum Event { /// An invocation attempt has started. #[prost(message, tag = "51")] @@ -280,7 +280,7 @@ pub mod build_event { } } /// Unique identifier for a build event stream. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct StreamId { /// The id of a Build message. #[prost(string, tag = "1")] @@ -383,7 +383,7 @@ impl ConsoleOutputStream { /// multiple invocations for a build (e.g. retries). /// - InvocationAttemptCompleted: When work for a build finishes. /// - BuildFinished: When a build is finished. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PublishLifecycleEventRequest { /// The interactivity of this build. #[prost(enumeration = "publish_lifecycle_event_request::ServiceLevel", tag = "1")] @@ -466,7 +466,7 @@ pub mod publish_lifecycle_event_request { } /// States which event has been committed. Any failure to commit will cause /// RPC errors, hence not recorded by this proto. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PublishBuildToolEventStreamResponse { /// The stream that contains this event. #[prost(message, optional, tag = "1")] @@ -477,7 +477,7 @@ pub struct PublishBuildToolEventStreamResponse { } /// Build event with contextual information about the stream it belongs to and /// its position in that stream. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct OrderedBuildEvent { /// Which build event stream this event belongs to. #[prost(message, optional, tag = "1")] @@ -492,7 +492,7 @@ pub struct OrderedBuildEvent { pub event: ::core::option::Option, } /// Streaming request message for PublishBuildToolEventStream. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct PublishBuildToolEventStreamRequest { /// Required. The build event with position info. /// New publishing clients should use this field rather than the 3 above. @@ -633,7 +633,7 @@ pub mod publish_build_event_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.devtools.build.v1.PublishBuildEvent/PublishLifecycleEvent", ); @@ -668,7 +668,7 @@ pub mod publish_build_event_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.devtools.build.v1.PublishBuildEvent/PublishBuildToolEventStream", ); @@ -857,7 +857,7 @@ pub mod publish_build_event_server { let inner = self.inner.clone(); let fut = async move { let method = PublishLifecycleEventSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -912,7 +912,7 @@ pub mod publish_build_event_server { let inner = self.inner.clone(); let fut = async move { let method = PublishBuildToolEventStreamSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, diff --git a/nativelink-proto/genproto/google.longrunning.pb.rs b/nativelink-proto/genproto/google.longrunning.pb.rs index fec578107..d5857361c 100644 --- a/nativelink-proto/genproto/google.longrunning.pb.rs +++ b/nativelink-proto/genproto/google.longrunning.pb.rs @@ -62,14 +62,14 @@ pub mod operation { } } /// The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetOperationRequest { /// The name of the operation resource. #[prost(string, tag = "1")] pub name: ::prost::alloc::string::String, } /// The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ListOperationsRequest { /// The name of the operation's parent resource. #[prost(string, tag = "4")] @@ -95,21 +95,21 @@ pub struct ListOperationsResponse { pub next_page_token: ::prost::alloc::string::String, } /// The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct CancelOperationRequest { /// The name of the operation resource to be cancelled. #[prost(string, tag = "1")] pub name: ::prost::alloc::string::String, } /// The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DeleteOperationRequest { /// The name of the operation resource to be deleted. #[prost(string, tag = "1")] pub name: ::prost::alloc::string::String, } /// The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct WaitOperationRequest { /// The name of the operation resource to wait on. #[prost(string, tag = "1")] @@ -131,7 +131,7 @@ pub struct WaitOperationRequest { /// metadata_type: "LongRunningRecognizeMetadata" /// }; /// } -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct OperationInfo { /// Required. The message name of the primary return type for this /// long-running operation. @@ -267,7 +267,7 @@ pub mod operations_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.longrunning.Operations/ListOperations", ); @@ -293,7 +293,7 @@ pub mod operations_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.longrunning.Operations/GetOperation", ); @@ -320,7 +320,7 @@ pub mod operations_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.longrunning.Operations/DeleteOperation", ); @@ -353,7 +353,7 @@ pub mod operations_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.longrunning.Operations/CancelOperation", ); @@ -385,7 +385,7 @@ pub mod operations_client { format!("Service was not ready: {}", e.into()), ) })?; - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( "/google.longrunning.Operations/WaitOperation", ); @@ -586,7 +586,7 @@ pub mod operations_server { let inner = self.inner.clone(); let fut = async move { let method = ListOperationsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -631,7 +631,7 @@ pub mod operations_server { let inner = self.inner.clone(); let fut = async move { let method = GetOperationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -676,7 +676,7 @@ pub mod operations_server { let inner = self.inner.clone(); let fut = async move { let method = DeleteOperationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -721,7 +721,7 @@ pub mod operations_server { let inner = self.inner.clone(); let fut = async move { let method = CancelOperationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, @@ -766,7 +766,7 @@ pub mod operations_server { let inner = self.inner.clone(); let fut = async move { let method = WaitOperationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); + let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( accept_compression_encodings, diff --git a/nativelink-proto/genproto/google.rpc.pb.rs b/nativelink-proto/genproto/google.rpc.pb.rs index 184db6250..199358ec1 100644 --- a/nativelink-proto/genproto/google.rpc.pb.rs +++ b/nativelink-proto/genproto/google.rpc.pb.rs @@ -104,14 +104,14 @@ pub struct ErrorInfo { /// the delay between retries based on `retry_delay`, until either a maximum /// number of retries have been reached or a maximum retry delay cap has been /// reached. -#[derive(Clone, Copy, PartialEq, ::prost::Message)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct RetryInfo { /// Clients should wait at least this long between retrying the same request. #[prost(message, optional, tag = "1")] pub retry_delay: ::core::option::Option<::prost_types::Duration>, } /// Describes additional debugging info. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DebugInfo { /// The stack trace entries indicating where the error occurred. #[prost(string, repeated, tag = "1")] @@ -241,7 +241,7 @@ pub struct PreconditionFailure { /// Nested message and enum types in `PreconditionFailure`. pub mod precondition_failure { /// A message type used to describe a single precondition failure. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Violation { /// The type of PreconditionFailure. We recommend using a service-specific /// enum type to define the supported precondition violation subjects. For @@ -272,7 +272,7 @@ pub struct BadRequest { /// Nested message and enum types in `BadRequest`. pub mod bad_request { /// A message type used to describe a single bad request field. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct FieldViolation { /// A path that leads to a field in the request body. The value will be a /// sequence of dot-separated identifiers that identify a protocol buffer @@ -332,7 +332,7 @@ pub mod bad_request { } /// Contains metadata about the request that clients can attach when filing a bug /// or providing other forms of feedback. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct RequestInfo { /// An opaque string that should only be interpreted by the service generating /// it. For example, it can be used to identify requests in the service's logs. @@ -344,7 +344,7 @@ pub struct RequestInfo { pub serving_data: ::prost::alloc::string::String, } /// Describes the resource that is being accessed. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct ResourceInfo { /// A name for the type of resource being accessed, e.g. "sql table", /// "cloud storage bucket", "file", "Google calendar"; or the type URL @@ -382,7 +382,7 @@ pub struct Help { /// Nested message and enum types in `Help`. pub mod help { /// Describes a URL link. - #[derive(Clone, PartialEq, ::prost::Message)] + #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct Link { /// Describes what the link offers. #[prost(string, tag = "1")] @@ -394,7 +394,7 @@ pub mod help { } /// Provides a localized error message that is safe to return to the user /// which can be attached to an RPC error. -#[derive(Clone, PartialEq, ::prost::Message)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct LocalizedMessage { /// The locale used following the specification defined at /// diff --git a/nativelink-redis-tester/Cargo.toml b/nativelink-redis-tester/Cargo.toml index cbb65e9ea..16f427d26 100644 --- a/nativelink-redis-tester/Cargo.toml +++ b/nativelink-redis-tester/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-redis-tester" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-util = { path = "../nativelink-util" } diff --git a/nativelink-redis-tester/src/dynamic_fake_redis.rs b/nativelink-redis-tester/src/dynamic_fake_redis.rs index ec33d3494..d3c408d00 100644 --- a/nativelink-redis-tester/src/dynamic_fake_redis.rs +++ b/nativelink-redis-tester/src/dynamic_fake_redis.rs @@ -22,6 +22,7 @@ use redis::Value; use redis_protocol::resp2::decode::decode; use redis_protocol::resp2::types::{OwnedFrame, Resp2Frame}; use tokio::net::TcpListener; +use tokio::sync::oneshot::{self, Sender}; use tracing::{debug, info, trace}; use crate::fake_redis::{arg_as_string, fake_redis_internal}; @@ -70,7 +71,7 @@ impl FakeRedisBackend { .replace(subscription_manager); } - async fn dynamic_fake_redis(self, listener: TcpListener) { + async fn dynamic_fake_redis(self, listener: TcpListener, listener_ready_tx: Sender<()>) { let inner = move |buf: &[u8]| -> String { let mut output = String::new(); let mut buf_index = 0; @@ -399,7 +400,7 @@ impl FakeRedisBackend { } output }; - fake_redis_internal(listener, vec![inner]).await; + fake_redis_internal(listener, listener_ready_tx, vec![inner]).await; } pub async fn run(self) -> u16 { @@ -407,10 +408,16 @@ impl FakeRedisBackend { let port = listener.local_addr().unwrap().port(); info!("Using port {port}"); + let (listener_ready_tx, listener_ready_rx) = oneshot::channel::<()>(); + background_spawn!("listener", async move { - self.dynamic_fake_redis(listener).await; + self.dynamic_fake_redis(listener, listener_ready_tx).await; }); + listener_ready_rx + .await + .expect("Expected successful listener boot"); + port } } diff --git a/nativelink-redis-tester/src/fake_redis.rs b/nativelink-redis-tester/src/fake_redis.rs index d80ed2152..95a49685b 100644 --- a/nativelink-redis-tester/src/fake_redis.rs +++ b/nativelink-redis-tester/src/fake_redis.rs @@ -21,6 +21,7 @@ use redis::Value; use redis_test::IntoRedisValue; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpListener; +use tokio::sync::oneshot::{self, Sender}; use tracing::{error, info, warn}; fn cmd_as_string(cmd: &redis::Cmd) -> String { @@ -198,16 +199,22 @@ pub fn fake_redis_sentinel_stream(master_name: &str, redis_port: u16) -> HashMap response } -pub(crate) async fn fake_redis_internal(listener: TcpListener, handlers: Vec) -where +pub(crate) async fn fake_redis_internal( + listener: TcpListener, + listener_ready_tx: Sender<()>, + handlers: Vec, +) where H: Fn(&[u8]) -> String + Send + Clone + 'static + Sync, { let mut handler_iter = handlers.iter().cloned().cycle(); + info!( + "Waiting for connection on {}", + listener.local_addr().unwrap() + ); + listener_ready_tx + .send(()) + .expect("Expected successful send"); loop { - info!( - "Waiting for connection on {}", - listener.local_addr().unwrap() - ); let Ok((mut stream, _)) = listener.accept().await else { error!("accept error"); panic!("error"); @@ -229,8 +236,11 @@ where } } -async fn fake_redis(listener: TcpListener, all_responses: Vec>) -where +async fn fake_redis( + listener: TcpListener, + listener_ready_tx: Sender<()>, + all_responses: Vec>, +) where B: BuildHasher + Clone + Send + 'static + Sync, { let funcs = all_responses @@ -254,7 +264,7 @@ where } }) .collect(); - fake_redis_internal(listener, funcs).await; + fake_redis_internal(listener, listener_ready_tx, funcs).await; } async fn make_fake_redis_with_multiple_responses( @@ -262,12 +272,18 @@ async fn make_fake_redis_with_multiple_responses u16 { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let port = listener.local_addr().unwrap().port(); - info!(port, "Fake redis booted"); + + let (listener_ready_tx, listener_ready_rx) = oneshot::channel::<()>(); background_spawn!("listener", async move { - fake_redis(listener, responses).await; + fake_redis(listener, listener_ready_tx, responses).await; }); + listener_ready_rx + .await + .expect("Expected successful listener boot"); + info!(port, "Fake redis booted"); + port } diff --git a/nativelink-redis-tester/src/read_only_redis.rs b/nativelink-redis-tester/src/read_only_redis.rs index fe5e92a9c..6e6dac730 100644 --- a/nativelink-redis-tester/src/read_only_redis.rs +++ b/nativelink-redis-tester/src/read_only_redis.rs @@ -22,6 +22,7 @@ use redis::Value; use redis_protocol::resp2::decode::decode; use redis_protocol::resp2::types::OwnedFrame; use tokio::net::TcpListener; +use tokio::sync::oneshot::{self, Sender}; use tracing::info; use crate::fake_redis::{arg_as_string, fake_redis_internal}; @@ -47,7 +48,7 @@ impl ReadOnlyRedis { } } - async fn dynamic_fake_redis(self, listener: TcpListener) { + async fn dynamic_fake_redis(self, listener: TcpListener, listener_ready_tx: Sender<()>) { let readonly_err_str = "READONLY You can't write against a read only replica."; let readonly_err = format!("!{}\r\n{readonly_err_str}\r\n", readonly_err_str.len()); @@ -149,7 +150,7 @@ impl ReadOnlyRedis { } output }; - fake_redis_internal(listener, vec![inner]).await; + fake_redis_internal(listener, listener_ready_tx, vec![inner]).await; } pub async fn run(self) -> u16 { @@ -157,10 +158,16 @@ impl ReadOnlyRedis { let port = listener.local_addr().unwrap().port(); info!("Using port {port}"); + let (listener_ready_tx, listener_ready_rx) = oneshot::channel::<()>(); + background_spawn!("listener", async move { - self.dynamic_fake_redis(listener).await; + self.dynamic_fake_redis(listener, listener_ready_tx).await; }); + listener_ready_rx + .await + .expect("Expected successful listener boot"); + port } } diff --git a/nativelink-scheduler/Cargo.toml b/nativelink-scheduler/Cargo.toml index e57468d3c..bc590cab7 100644 --- a/nativelink-scheduler/Cargo.toml +++ b/nativelink-scheduler/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-scheduler" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-config = { path = "../nativelink-config" } @@ -21,13 +21,13 @@ futures = { version = "0.3.31", default-features = false } humantime = { version = "2.3.0", default-features = false } lru = { version = "0.16.0", default-features = false } mock_instant = { version = "0.5.3", default-features = false } -opentelemetry = { version = "0.30.0", default-features = false } -opentelemetry-semantic-conventions = { version = "0.30.0", default-features = false, features = [ +opentelemetry = { version = "0.32.0", default-features = false } +opentelemetry-semantic-conventions = { version = "0.32.0", default-features = false, features = [ "default", "semconv_experimental", ] } parking_lot = { version = "0.12.3", default-features = false } -prost = { version = "0.13.5", default-features = false } +prost = { version = "0.14.4", default-features = false } redis = { version = "1.0.0", default-features = false } scopeguard = { version = "1.2.0", default-features = false } serde = { version = "1.0.219", features = ["rc"], default-features = false } @@ -42,7 +42,7 @@ tokio = { version = "1.52.2", features = [ tokio-stream = { version = "0.1.17", features = [ "fs", ], default-features = false } -tonic = { version = "0.13.0", features = [ +tonic = { version = "0.14.0", features = [ "tls-ring", "transport", ], default-features = false } @@ -59,6 +59,9 @@ nativelink-redis-tester = { path = "../nativelink-redis-tester" } pretty_assertions = { version = "1.4.1", features = [ "std", ], default-features = false } +tokio = { version = "1.52.2", features = [ + "test-util", +], default-features = false } tracing-test = { version = "0.2.5", default-features = false, features = [ "no-env-filter", ] } diff --git a/nativelink-scheduler/src/api_worker_scheduler.rs b/nativelink-scheduler/src/api_worker_scheduler.rs index 25b727d0b..2a79d0582 100644 --- a/nativelink-scheduler/src/api_worker_scheduler.rs +++ b/nativelink-scheduler/src/api_worker_scheduler.rs @@ -31,6 +31,11 @@ use nativelink_proto::com::github::trace_machina::nativelink::events::{ }; use nativelink_proto::com::github::trace_machina::nativelink::remote_execution::ActionResourceUsage; use nativelink_util::action_messages::{OperationId, WorkerId}; +use nativelink_util::metrics::{ + WorkerDisconnectReason, record_execution_cpu_time, record_execution_peak_memory, + record_worker_connected, record_worker_disconnected, record_worker_keepalive, + record_worker_state, +}; use nativelink_util::operation_state_manager::{UpdateOperationType, WorkerStateManager}; use nativelink_util::origin_event::get_node_id; use nativelink_util::platform_properties::PlatformProperties; @@ -179,6 +184,7 @@ impl ApiWorkerSchedulerImpl { running_operations = worker.running_action_infos.len(), "Worker keepalive received" ); + record_worker_keepalive(); Ok(()) } @@ -188,7 +194,9 @@ impl ApiWorkerSchedulerImpl { fn add_worker(&mut self, worker: Worker) -> Result<(), Error> { let worker_id = worker.id.clone(); let platform_properties = worker.platform_properties.clone(); - self.workers.put(worker_id.clone(), worker); + // A replacement is one out and one in, so the gauge only moves for a + // genuinely new worker. + let replaced = self.workers.put(worker_id.clone(), worker); // Add to capability index for fast matching self.capability_index @@ -208,6 +216,16 @@ impl ApiWorkerSchedulerImpl { "Worker connection appears to have been closed while adding to pool" ); } + if let Some(replaced) = &replaced { + if replaced.is_draining { + record_worker_state("draining", false); + } + if replaced.is_paused { + record_worker_state("paused", false); + } + } else { + record_worker_connected(); + } self.worker_change_notify.notify_one(); res } @@ -234,6 +252,9 @@ impl ApiWorkerSchedulerImpl { .workers .get_mut(worker_id) .err_tip(|| format!("Worker {worker_id} doesn't exist in the pool"))?; + if worker.is_draining != is_draining { + record_worker_state("draining", is_draining); + } worker.is_draining = is_draining; self.worker_change_notify.notify_one(); Ok(()) @@ -353,41 +374,50 @@ impl ApiWorkerSchedulerImpl { }; // Update the operation in the worker state manager. - { - let update_operation_res = self - .worker_state_manager - .update_operation(operation_id, worker_id, update) - .await - .err_tip(|| "in update_operation on SimpleScheduler::update_action"); - if let Err(err) = update_operation_res { - error!( - %operation_id, - ?worker_id, - ?err, - "Failed to update_operation on update_action" - ); - return Err(err); - } + let update_operation_res = self + .worker_state_manager + .update_operation(operation_id, worker_id, update) + .await + .err_tip(|| "in update_operation on SimpleScheduler::update_action"); + if let Err(err) = &update_operation_res { + error!( + %operation_id, + ?worker_id, + ?err, + "Failed to update_operation on update_action" + ); } if !is_finished { - return Ok(()); + return update_operation_res; } + // The worker is done with this action even if the state-manager update + // failed (e.g. the operation was already torn down after its clients + // timed out). The worker bookkeeping below must still run, or the + // worker's platform properties leak until it can never match again. // Clear this action from the current worker if finished. let complete_action_res = { // Note: We need to run this before dealing with backpressure logic. + let was_paused = worker.is_paused; let complete_action_res = worker.complete_action(operation_id).await; if (due_to_backpressure || !worker.can_accept_work()) && worker.has_actions() { worker.is_paused = true; } + // complete_action clears is_paused on its way through, so compare + // the state either side of it rather than testing the flag after. + // Testing afterwards counts a re-pause every time and never + // unwinds, which leaves the gauge climbing forever. + if was_paused != worker.is_paused { + record_worker_state("paused", worker.is_paused); + } complete_action_res }; self.worker_change_notify.notify_one(); - complete_action_res + update_operation_res.merge(complete_action_res) } /// Notifies the specified worker to run the given action and handles errors by evicting @@ -459,6 +489,27 @@ impl ApiWorkerSchedulerImpl { ) -> Result<(), Error> { let mut result = Ok(()); if let Some(mut worker) = self.remove_worker(worker_id) { + // Log every eviction here rather than in each caller, so a worker + // can never leave the pool unexplained. Without this, a worker that + // vanished mid-build left nothing on the scheduler side to + // attribute it to, and the only visible symptom was the worker + // reconnecting with a fresh id. + info!( + ?worker_id, + is_disconnect, + running_actions = worker.running_action_infos.len(), + reason = %err.message_string(), + "Evicting worker from pool" + ); + record_worker_disconnected( + if is_disconnect { + WorkerDisconnectReason::Disconnected + } else { + WorkerDisconnectReason::Evicted + }, + worker.is_draining, + worker.is_paused, + ); // We don't care if we fail to send message to worker, this is only a best attempt. drop(worker.notify_update(WorkerUpdate::Disconnect).await); let update = if is_disconnect { @@ -648,6 +699,17 @@ impl WorkerScheduler for ApiWorkerScheduler { // only override lived on `SimpleScheduler`, which this path never // reaches, so the event was silently dropped by the trait's no-op // default and `observed_worker_peak_memory_mib` was never recorded. + // Sampling is optional, so only record when the worker actually took a + // reading. A zero here means "not sampled", not "used no memory". + if resource_usage.sampled { + if resource_usage.peak_memory_kb > 0 { + record_execution_peak_memory(resource_usage.peak_memory_kb, ""); + } + if resource_usage.cpu_time_ms > 0 { + record_execution_cpu_time(resource_usage.cpu_time_ms, ""); + } + } + let Some(origin_event_tx) = self.maybe_origin_event_tx.as_ref() else { return Ok(()); }; diff --git a/nativelink-scheduler/src/awaited_action_db/awaited_action.rs b/nativelink-scheduler/src/awaited_action_db/awaited_action.rs index fb8d57bd1..e32b7bdba 100644 --- a/nativelink-scheduler/src/awaited_action_db/awaited_action.rs +++ b/nativelink-scheduler/src/awaited_action_db/awaited_action.rs @@ -211,7 +211,7 @@ impl AwaitedAction { } /// Sets the worker id that is currently processing this action. - pub(crate) fn set_worker_id(&mut self, new_maybe_worker_id: Option, now: SystemTime) { + pub fn set_worker_id(&mut self, new_maybe_worker_id: Option, now: SystemTime) { if self.worker_id != new_maybe_worker_id { self.worker_id = new_maybe_worker_id; self.worker_keep_alive(now); diff --git a/nativelink-scheduler/src/awaited_action_db/mod.rs b/nativelink-scheduler/src/awaited_action_db/mod.rs index 315f13e67..28de3239d 100644 --- a/nativelink-scheduler/src/awaited_action_db/mod.rs +++ b/nativelink-scheduler/src/awaited_action_db/mod.rs @@ -24,6 +24,8 @@ use nativelink_metric::MetricsComponent; use nativelink_util::action_messages::{ActionInfo, ActionStage, OperationId}; use serde::{Deserialize, Serialize}; +use crate::worker_registry::SharedWorkerRegistry; + mod awaited_action; /// Duration to wait before sending client keep alive messages. @@ -188,4 +190,9 @@ pub trait AwaitedActionDb: Send + Sync + MetricsComponent + Unpin + 'static { action_info: Arc, no_event_action_timeout: Duration, ) -> impl Future> + Send; + + /// Lets an implementation judge worker liveness before deciding an + /// executing action was abandoned. Only shared-state implementations + /// need it, so the default ignores the registry. + fn set_worker_registry(&mut self, _worker_registry: SharedWorkerRegistry) {} } diff --git a/nativelink-scheduler/src/memory_awaited_action_db.rs b/nativelink-scheduler/src/memory_awaited_action_db.rs index 6dc73e2ca..8cc5c4be7 100644 --- a/nativelink-scheduler/src/memory_awaited_action_db.rs +++ b/nativelink-scheduler/src/memory_awaited_action_db.rs @@ -417,12 +417,18 @@ impl I + Clone + Send + Sync> AwaitedActionDbI // Cleanup action_info_hash_key_to_awaited_action if it was marked cached. match &awaited_action.action_info().unique_qualifier { ActionUniqueQualifier::Cacheable(action_key) => { - let maybe_awaited_action = self + // Once this operation finished, a newer operation for the + // same action key may have claimed the entry; removing it + // unconditionally here would orphan that operation's + // deduplication entry. + let owned_by_this_operation = self .action_info_hash_key_to_awaited_action - .remove(action_key); - if !awaited_action.state().stage.is_finished() - && maybe_awaited_action.is_none() - { + .get(action_key) + .is_some_and(|id| id == &operation_id); + if owned_by_this_operation { + self.action_info_hash_key_to_awaited_action + .remove(action_key); + } else if !awaited_action.state().stage.is_finished() { error!( %operation_id, ?awaited_action, @@ -550,18 +556,19 @@ impl I + Clone + Send + Sync> AwaitedActionDbI } match &new_awaited_action.action_info().unique_qualifier { ActionUniqueQualifier::Cacheable(action_key) => { - let maybe_awaited_action = - action_info_hash_key_to_awaited_action.remove(action_key); - match maybe_awaited_action { - Some(removed_operation_id) => { - if &removed_operation_id != new_awaited_action.operation_id() { - error!( - ?removed_operation_id, - ?new_awaited_action, - ?action_key, - "action_info_hash_key_to_awaited_action and operation_id_to_awaited_action are out of sync", - ); - } + match action_info_hash_key_to_awaited_action.get(action_key) { + Some(owning_operation_id) + if owning_operation_id == new_awaited_action.operation_id() => {} + Some(owning_operation_id) => { + // The entry belongs to a newer operation for the same + // action key; leave it in place. + error!( + ?owning_operation_id, + ?new_awaited_action, + ?action_key, + "action_info_hash_key_to_awaited_action and operation_id_to_awaited_action are out of sync", + ); + return; } None => { error!( @@ -569,8 +576,10 @@ impl I + Clone + Send + Sync> AwaitedActionDbI ?action_key, "action_info_hash_key_to_awaited_action out of sync, it should have had the unique_key", ); + return; } } + action_info_hash_key_to_awaited_action.remove(action_key); } ActionUniqueQualifier::Uncacheable(_action_key) => { // If we are not cacheable, the action should not be in the diff --git a/nativelink-scheduler/src/simple_scheduler.rs b/nativelink-scheduler/src/simple_scheduler.rs index 0abd6bad7..5a72b9f50 100644 --- a/nativelink-scheduler/src/simple_scheduler.rs +++ b/nativelink-scheduler/src/simple_scheduler.rs @@ -27,6 +27,7 @@ use nativelink_proto::com::github::trace_machina::nativelink::events::{ use nativelink_proto::com::github::trace_machina::nativelink::remote_execution::StartExecute; use nativelink_util::action_messages::{ActionInfo, ActionState, OperationId, WorkerId}; use nativelink_util::instant_wrapper::InstantWrapper; +use nativelink_util::metrics::record_matching_pass; use nativelink_util::operation_state_manager::{ ActionStateResult, ActionStateResultStream, ClientStateManager, MatchingEngineStateManager, OperationFilter, OperationStageFlags, OrderDirection, UpdateOperationType, @@ -275,6 +276,13 @@ impl SimpleScheduler { // can create a map of capabilities of each worker and then try and match // the actions to the worker using the map lookup (ie. map reduce). async fn do_try_match(&self, full_worker_logging: bool) -> Result<(), Error> { + let match_started = Instant::now(); + let result = self.do_try_match_inner(full_worker_logging).await; + record_matching_pass(match_started.elapsed().as_secs_f64(), result.is_ok()); + result + } + + async fn do_try_match_inner(&self, full_worker_logging: bool) -> Result<(), Error> { async fn match_action_to_worker( action_state_result: &dyn ActionStateResult, workers: &ApiWorkerScheduler, @@ -468,7 +476,7 @@ impl SimpleScheduler { NowFn: Fn() -> I + Clone + Send + Unpin + Sync + 'static, >( spec: &SimpleSpec, - awaited_action_db: A, + mut awaited_action_db: A, on_matching_engine_run: F, task_change_notify: Arc, now_fn: NowFn, @@ -510,6 +518,10 @@ impl SimpleScheduler { // Create shared worker registry for single heartbeat per worker. let worker_registry = Arc::new(WorkerRegistry::new()); + // The db decides on its own whether an executing action was abandoned, + // so it needs the same liveness view the state manager uses. + awaited_action_db.set_worker_registry(worker_registry.clone()); + let state_manager = SimpleSchedulerStateManager::new( max_job_retries, Duration::from_secs(worker_timeout_s), @@ -532,6 +544,12 @@ impl SimpleScheduler { let worker_scheduler_clone = worker_scheduler.clone(); + let fallback_match_interval = match spec.fallback_match_interval_s { + // Zero or any negative value means disabled. + ..=0 => None, + secs => Some(Duration::from_secs(secs.unsigned_abs())), + }; + let action_scheduler = Arc::new_cyclic(move |weak_self| -> Self { let weak_inner = weak_self.clone(); let task_worker_matching_spawn = @@ -546,16 +564,28 @@ impl SimpleScheduler { tokio::pin!(worker_change_fut); // Wait for either of these futures to be ready. let state_changed = future::select(task_change_fut, worker_change_fut); - if last_match_successful { - let _ = state_changed.await; + let max_wait = if last_match_successful { + // Even on success, periodically re-run the match as a + // fallback for missed notifications and eventually + // consistent backends (e.g. a re-queued operation that + // was not yet visible to the search triggered by its + // own notification). Without this, such an operation + // can stay queued until an unrelated event triggers + // another matching pass. + fallback_match_interval } else { // If the last match failed, then run again after a short sleep. // This resolves issues where we tried to re-schedule a job to // a disconnected worker. The sleep ensures we don't enter a // hard loop if there's something wrong inside do_try_match. - let sleep_fut = tokio::time::sleep(Duration::from_millis(100)); + Some(Duration::from_millis(100)) + }; + if let Some(max_wait) = max_wait { + let sleep_fut = tokio::time::sleep(max_wait); tokio::pin!(sleep_fut); let _ = future::select(state_changed, sleep_fut).await; + } else { + let _ = state_changed.await; } let result = match weak_inner.upgrade() { diff --git a/nativelink-scheduler/src/simple_scheduler_state_manager.rs b/nativelink-scheduler/src/simple_scheduler_state_manager.rs index 0e210ea92..66fbcb466 100644 --- a/nativelink-scheduler/src/simple_scheduler_state_manager.rs +++ b/nativelink-scheduler/src/simple_scheduler_state_manager.rs @@ -41,7 +41,7 @@ use tracing::{debug, info, trace, warn}; use super::awaited_action_db::{ AwaitedAction, AwaitedActionDb, AwaitedActionSubscriber, SortedAwaitedActionState, }; -use crate::worker_registry::SharedWorkerRegistry; +use crate::worker_registry::{ORPHANED_ACTION_TIMEOUT, SharedWorkerRegistry, WorkerLiveness}; /// Maximum number of times an update to the database /// can fail before giving up. @@ -367,34 +367,57 @@ where } } - let registry_alive = if let Some(ref worker_registry) = self.worker_registry { - if let Some(worker_id) = awaited_action.worker_id() { + let liveness = match (&self.worker_registry, awaited_action.worker_id()) { + (Some(worker_registry), Some(worker_id)) => { worker_registry - .is_worker_alive(worker_id, self.no_event_action_timeout, now) + .check_liveness(worker_id, self.no_event_action_timeout, now) .await - } else { - false } - } else { - false + // No registry, or not assigned yet: fall back to the + // timestamp-only check. + _ => WorkerLiveness::Stale, }; - if registry_alive { - if self.max_executing_timeout > Duration::ZERO { + match liveness { + // Ours and heartbeating: only the stuck-but-alive ceiling applies, + // and disabling that means no ceiling on a live worker. + WorkerLiveness::Alive => { + if self.max_executing_timeout > Duration::ZERO { + let last_update = awaited_action.last_worker_updated_timestamp(); + if let Ok(elapsed) = now.duration_since(last_update) { + return elapsed > self.max_executing_timeout; + } + } + false + } + + // Usually a peer's healthy worker, so worker_timeout_s must not + // apply. It can also be an orphan no instance will ever reap, and + // max_action_executing_timeout_s defaults to disabled, so fall + // back to a ceiling rather than never timing out. + WorkerLiveness::Unknown => { + let ceiling = if self.max_executing_timeout > Duration::ZERO { + self.max_executing_timeout + } else { + ORPHANED_ACTION_TIMEOUT + }; let last_update = awaited_action.last_worker_updated_timestamp(); - if let Ok(elapsed) = now.duration_since(last_update) { - return elapsed > self.max_executing_timeout; + match now.duration_since(last_update) { + Ok(elapsed) => elapsed > ceiling, + Err(_) => false, } } - return false; - } - let worker_should_update_before = awaited_action - .last_worker_updated_timestamp() - .checked_add(self.no_event_action_timeout) - .unwrap_or(now); + // Registered here and gone quiet: ours, and it looks dead. + WorkerLiveness::Stale => { + let worker_should_update_before = awaited_action + .last_worker_updated_timestamp() + .checked_add(self.no_event_action_timeout) + .unwrap_or(now); - worker_should_update_before < now + worker_should_update_before < now + } + } } async fn apply_filter_predicate( @@ -571,41 +594,13 @@ where .await .err_tip(|| "In SimpleSchedulerStateManager::timeout_operation_id")?; - // If the action is not executing, we should not timeout the action. - if !matches!(awaited_action.state().stage, ActionStage::Executing) { - return Ok(()); - } - - let now = (self.now_fn)().now(); - - // Check worker liveness via registry if available. - let registry_alive = if let Some(ref worker_registry) = self.worker_registry { - if let Some(worker_id) = awaited_action.worker_id() { - worker_registry - .is_worker_alive(worker_id, self.no_event_action_timeout, now) - .await - } else { - false - } - } else { - false - }; - - let timestamp_alive = { - let worker_should_update_before = awaited_action - .last_worker_updated_timestamp() - .checked_add(self.no_event_action_timeout) - .unwrap_or(now); - worker_should_update_before >= now - }; - - if registry_alive || timestamp_alive { + // Re-check under the lock against freshly loaded state, and delegate + // rather than re-deriving the rule: the two copies had drifted. + if !self.should_timeout_operation(&awaited_action).await { trace!( %operation_id, worker_id = ?awaited_action.worker_id(), - registry_alive, - timestamp_alive, - "Worker is alive, operation not timed out" + "Operation no longer needs timing out, skipping" ); return Ok(()); } @@ -613,9 +608,7 @@ where warn!( %operation_id, worker_id = ?awaited_action.worker_id(), - registry_alive, - timestamp_alive, - "Worker not alive via registry or timestamp, timing out operation" + "Timing out operation" ); self.assign_operation( @@ -747,6 +740,7 @@ where } } + let mut is_retry = false; let stage = match &update { UpdateOperationType::KeepAlive => { awaited_action.worker_keep_alive((self.now_fn)().now()); @@ -795,6 +789,7 @@ where ..ActionResult::default() }) } else { + is_retry = true; ActionStage::Queued } } @@ -826,6 +821,7 @@ where ..ActionResult::default() }) } else { + is_retry = true; ActionStage::Queued } } @@ -920,6 +916,12 @@ where }; attrs.push(KeyValue::new(EXECUTION_RESULT, result)); EXECUTION_METRICS.execution_completed_count.add(1, &attrs); + nativelink_util::metrics::record_completed_execution_metrics( + action_result, + instance_name, + worker_id.as_deref(), + priority, + ); } ActionStage::CompletedFromCache(_) => { attrs.push(KeyValue::new(EXECUTION_RESULT, ExecutionResult::CacheHit)); @@ -928,6 +930,16 @@ where _ => {} } + // A failed attempt that re-queued the action counts as a retry. + if is_retry { + let retry_attrs = nativelink_util::metrics::make_execution_attributes( + instance_name, + worker_id.as_deref(), + priority, + ); + EXECUTION_METRICS.execution_retry_count.add(1, &retry_attrs); + } + debug!( %operation_id, retry_count, diff --git a/nativelink-scheduler/src/store_awaited_action_db.rs b/nativelink-scheduler/src/store_awaited_action_db.rs index c40bbb963..70357e19c 100644 --- a/nativelink-scheduler/src/store_awaited_action_db.rs +++ b/nativelink-scheduler/src/store_awaited_action_db.rs @@ -18,7 +18,7 @@ use core::sync::atomic::{AtomicU64, Ordering}; use core::time::Duration; use std::borrow::Cow; use std::sync::{Arc, Weak}; -use std::time::UNIX_EPOCH; +use std::time::{SystemTime, UNIX_EPOCH}; use bytes::Bytes; use futures::{Stream, TryStreamExt}; @@ -42,6 +42,7 @@ use crate::awaited_action_db::{ AwaitedAction, AwaitedActionDb, AwaitedActionSubscriber, CLIENT_KEEPALIVE_DURATION, SortedAwaitedAction, SortedAwaitedActionState, }; +use crate::worker_registry::{ORPHANED_ACTION_TIMEOUT, SharedWorkerRegistry, WorkerLiveness}; type ClientOperationId = OperationId; @@ -136,9 +137,8 @@ where } // Helper to convert SystemTime to unix timestamp - let to_unix_ts = |t: std::time::SystemTime| -> u64 { - t.duration_since(UNIX_EPOCH).map_or(0, |d| d.as_secs()) - }; + let to_unix_ts = + |t: SystemTime| -> u64 { t.duration_since(UNIX_EPOCH).map_or(0, |d| d.as_secs()) }; // Check the separate keepalive key for the most recent timestamp. let keepalive_ts = if USE_SEPARATE_CLIENT_KEEPALIVE_KEY { @@ -383,7 +383,7 @@ const CLIENT_ID_TO_OPERATION_ID_KEY_PREFIX: &str = "cid_"; /// TTL bounding the cid_* mapping's lifetime so it cannot outlive its /// aa_* key and accumulate as a permanent orphan (24h safely exceeds /// any real action lifetime). -const CLIENT_ID_MAPPING_TTL: Duration = Duration::from_secs(24 * 60 * 60); +const CLIENT_ID_MAPPING_TTL: Duration = Duration::from_hours(24); /// Phase 2: Separate key prefix for client keepalives (non-versioned). const CLIENT_KEEPALIVE_KEY_PREFIX: &str = "ck_"; @@ -630,6 +630,7 @@ where operation_id_creator: F, _pull_task_change_subscriber_spawn: JoinHandleDropGuard<()>, retain_completed_for: Duration, + worker_registry: Option, } impl StoreAwaitedActionDb @@ -681,9 +682,55 @@ where operation_id_creator, _pull_task_change_subscriber_spawn: pull_task_change_subscriber, retain_completed_for: Duration::from_secs(retain_completed_for_s.into()), + worker_registry: None, }) } + /// Whether an executing action looks abandoned and should be recreated + /// rather than joined. + /// + /// `last_worker_updated_timestamp` lives in the shared store and + /// heartbeats never refresh it, so on its own it goes stale on any action + /// outliving `worker_timeout_s` and a healthy worker looks abandoned. + /// Consult the registry first and only fall back to the timestamp for + /// workers this instance owns. + #[expect(clippy::future_not_send)] // TODO(jhpratt) remove this + async fn executing_action_is_abandoned( + &self, + awaited_action: &AwaitedAction, + no_event_action_timeout: Duration, + now: SystemTime, + ) -> bool { + if awaited_action.state().stage != ActionStage::Executing { + return false; + } + + let liveness = match (&self.worker_registry, awaited_action.worker_id()) { + (Some(worker_registry), Some(worker_id)) => { + worker_registry + .check_liveness(worker_id, no_event_action_timeout, now) + .await + } + // No registry, or not assigned yet: timestamp only, as before. + _ => WorkerLiveness::Stale, + }; + + let ceiling = match liveness { + // Ours and heartbeating. Never recreate: that forks a second + // execution of work already running. + WorkerLiveness::Alive => return false, + // Ours and gone quiet. + WorkerLiveness::Stale => no_event_action_timeout, + // A peer's worker, or an orphan nobody owns. + WorkerLiveness::Unknown => ORPHANED_ACTION_TIMEOUT, + }; + + awaited_action + .last_worker_updated_timestamp() + .checked_add(ceiling) + .is_some_and(|deadline| deadline < now) + } + // `pub` so integration tests in `tests/` can drive this directly; // matches the precedent of `inner_update_awaited_action` below. #[expect(clippy::future_not_send)] // TODO(jhpratt) remove this @@ -731,17 +778,14 @@ where // If the existing job failed then we need to set back to queued or we get // a version mismatch. Equally we need to check the timeout as the job // may be abandoned in the store. - let worker_should_update_before = (awaited_action.state().stage - == ActionStage::Executing) - .then_some(()) - .map(|()| awaited_action.last_worker_updated_timestamp()) - .and_then(|last_worker_updated| { - last_worker_updated.checked_add(no_event_action_timeout) - }); - let awaited_action = if awaited_action.state().stage.is_finished() - || worker_should_update_before - .is_some_and(|timestamp| timestamp < (self.now_fn)().now()) - { + let abandoned = self + .executing_action_is_abandoned( + &awaited_action, + no_event_action_timeout, + (self.now_fn)().now(), + ) + .await; + let awaited_action = if awaited_action.state().stage.is_finished() || abandoned { tracing::debug!( "Recreating action {:?} for operation {client_operation_id}", awaited_action.action_info().digest() @@ -952,6 +996,10 @@ where } } + fn set_worker_registry(&mut self, worker_registry: SharedWorkerRegistry) { + self.worker_registry = Some(worker_registry); + } + async fn get_range_of_actions( &self, state: SortedAwaitedActionState, diff --git a/nativelink-scheduler/src/worker_capability_index.rs b/nativelink-scheduler/src/worker_capability_index.rs index b0e45b76b..1453a1217 100644 --- a/nativelink-scheduler/src/worker_capability_index.rs +++ b/nativelink-scheduler/src/worker_capability_index.rs @@ -91,7 +91,7 @@ impl WorkerCapabilityIndex { .insert(worker_id.clone()); } PlatformPropertyValue::Minimum(_) | PlatformPropertyValue::Ignore(_) => { - // Minimum properties are tracked via property_presence only. + // Minimum properties are tracked via `property_presence` only. // Their actual values are checked at runtime since they're dynamic. // Ignore properties we just drop diff --git a/nativelink-scheduler/src/worker_registry.rs b/nativelink-scheduler/src/worker_registry.rs index d9f885577..08cbcce3d 100644 --- a/nativelink-scheduler/src/worker_registry.rs +++ b/nativelink-scheduler/src/worker_registry.rs @@ -21,7 +21,33 @@ use async_lock::RwLock; use nativelink_util::action_messages::WorkerId; use tracing::{debug, trace}; +/// Ceiling for an action whose worker no instance here recognises. Long on +/// purpose: heartbeats never reach the shared state, so a healthy hour-long +/// action and an abandoned one look identical from here, and acting early +/// costs live work. +pub const ORPHANED_ACTION_TIMEOUT: Duration = Duration::from_hours(1); + +/// What this scheduler instance knows about a worker's liveness. +/// +/// A worker only appears in the registry of the instance holding its +/// `connect_worker` stream, so `Unknown` means "not mine to judge", not +/// "dead". +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum WorkerLiveness { + /// Registered here and has heartbeat within the timeout. + Alive, + /// Registered here, but has not been heard from within the timeout. + Stale, + /// Not registered here at all. Either connected to a different scheduler + /// instance, or already evicted (in which case its actions were requeued + /// at eviction time and no longer reference it). + Unknown, +} + /// In-memory worker registry that tracks worker liveness. +/// +/// Per-process: fed by the `connect_worker` streams this instance owns, not a +/// view of every worker in the deployment. #[derive(Debug)] pub struct WorkerRegistry { workers: RwLock>, @@ -60,30 +86,44 @@ impl WorkerRegistry { debug!(?worker_id, "FLOW: Worker removed from registry"); } - pub async fn is_worker_alive( + /// Liveness as far as THIS instance can tell. Callers acting on "dead" + /// must handle `Unknown` separately. + pub async fn check_liveness( &self, worker_id: &WorkerId, timeout: Duration, now: SystemTime, - ) -> bool { + ) -> WorkerLiveness { let workers = self.workers.read().await; - if let Some(last_seen) = workers.get(worker_id) - && let Some(deadline) = last_seen.checked_add(timeout) - { - let is_alive = deadline > now; - trace!( - ?worker_id, - last_seen = %humantime::format_rfc3339(*last_seen), - ?timeout, - is_alive, - "FLOW: Worker liveness check" - ); - return is_alive; - } + let Some(last_seen) = workers.get(worker_id) else { + trace!(?worker_id, "FLOW: Worker not registered on this instance"); + return WorkerLiveness::Unknown; + }; + + // An overflowing deadline can only be clock skew; treat as alive. + let liveness = match last_seen.checked_add(timeout) { + Some(deadline) if deadline > now => WorkerLiveness::Alive, + Some(_) => WorkerLiveness::Stale, + None => WorkerLiveness::Alive, + }; + trace!( + ?worker_id, + last_seen = %humantime::format_rfc3339(*last_seen), + ?timeout, + ?liveness, + "FLOW: Worker liveness check" + ); + liveness + } - trace!(?worker_id, "FLOW: Worker not found or timed out"); - false + pub async fn is_worker_alive( + &self, + worker_id: &WorkerId, + timeout: Duration, + now: SystemTime, + ) -> bool { + self.check_liveness(worker_id, timeout, now).await == WorkerLiveness::Alive } pub async fn get_worker_last_seen(&self, worker_id: &WorkerId) -> Option { @@ -138,6 +178,42 @@ mod tests { ); } + #[nativelink_test] + async fn test_check_liveness_distinguishes_stale_from_unknown() { + let registry = WorkerRegistry::new(); + let mine = WorkerId::from(String::from("mine")); + let theirs = WorkerId::from(String::from("belongs-to-another-instance")); + let now = SystemTime::now(); + let timeout = Duration::from_secs(5); + + // Never registered here. This is the case that must NOT read as dead: + // with several schedulers on shared state it is a peer's worker. + assert_eq!( + registry.check_liveness(&theirs, timeout, now).await, + WorkerLiveness::Unknown + ); + + registry.register_worker(&mine, now).await; + assert_eq!( + registry.check_liveness(&mine, timeout, now).await, + WorkerLiveness::Alive + ); + + // Registered here but gone quiet: genuinely ours and genuinely dead. + let later = now.checked_add(Duration::from_secs(10)).unwrap(); + assert_eq!( + registry.check_liveness(&mine, timeout, later).await, + WorkerLiveness::Stale + ); + + // Eviction takes it back to Unknown, not Stale. + registry.remove_worker(&mine).await; + assert_eq!( + registry.check_liveness(&mine, timeout, later).await, + WorkerLiveness::Unknown + ); + } + #[nativelink_test] async fn test_remove_worker() { let registry = WorkerRegistry::new(); diff --git a/nativelink-scheduler/tests/redis_store_awaited_action_db_test.rs b/nativelink-scheduler/tests/redis_store_awaited_action_db_test.rs index 0fd6e4c94..be75aed43 100644 --- a/nativelink-scheduler/tests/redis_store_awaited_action_db_test.rs +++ b/nativelink-scheduler/tests/redis_store_awaited_action_db_test.rs @@ -116,7 +116,7 @@ fn make_awaited_action(operation_id: &str) -> AwaitedAction { ) } -// TODO: This test needs to be rewritten to use workers (like test_multiple_clients_subscribe_to_same_action). +// TODO: This test needs to be rewritten to use workers (like `test_multiple_clients_subscribe_to_same_action`). #[nativelink_test] #[ignore = "needs rewrite to use workers (like test_multiple_clients_subscribe_to_same_action)"] async fn add_action_smoke_test() -> Result<(), Error> { @@ -288,7 +288,7 @@ async fn test_multiple_clients_subscribe_to_same_action() -> Result<(), Error> { .await .unwrap(); - // Second client should be able to get the action by its client_operation_id + // Second client should be able to get the action by its `client_operation_id` let get_subscription = scheduler .filter_operations(OperationFilter { client_operation_id: Some(OperationId::from(CLIENT_OPERATION_ID_2)), @@ -471,7 +471,7 @@ async fn test_orphaned_client_operation_id_returns_none() -> Result<(), Error> { fake_redis_backend.set_subscription_manager(store.subscription_manager().await.unwrap()); // Manually set up the orphaned state in the fake backend: - // 1. Add client_id → operation_id mapping (cid_* key) + // 1. Add `client_id` → `operation_id` mapping (cid_* key) { let mut table = fake_redis_backend.table.lock().unwrap(); let mut client_fields = HashMap::new(); diff --git a/nativelink-scheduler/tests/simple_scheduler_state_manager_test.rs b/nativelink-scheduler/tests/simple_scheduler_state_manager_test.rs index 3d2651be0..1a3807008 100644 --- a/nativelink-scheduler/tests/simple_scheduler_state_manager_test.rs +++ b/nativelink-scheduler/tests/simple_scheduler_state_manager_test.rs @@ -1,12 +1,21 @@ use core::time::Duration; +use std::collections::HashMap; use std::sync::Arc; use std::time::SystemTime; +use mock_instant::thread_local::MockClock; use nativelink_error::Error; use nativelink_macro::nativelink_test; +use nativelink_scheduler::awaited_action_db::AwaitedAction; use nativelink_scheduler::default_scheduler_factory::memory_awaited_action_db_factory; use nativelink_scheduler::simple_scheduler_state_manager::SimpleSchedulerStateManager; -use nativelink_util::action_messages::{OperationId, WorkerId}; +use nativelink_scheduler::worker_registry::WorkerRegistry; +use nativelink_util::action_messages::{ + ActionInfo, ActionStage, ActionState, ActionUniqueKey, ActionUniqueQualifier, OperationId, + WorkerId, +}; +use nativelink_util::common::DigestInfo; +use nativelink_util::digest_hasher::DigestHasherFunc; use nativelink_util::instant_wrapper::MockInstantWrapped; use nativelink_util::operation_state_manager::{UpdateOperationType, WorkerStateManager}; use tokio::sync::Notify; @@ -44,3 +53,230 @@ async fn drops_missing_actions() -> Result<(), Error> { )); Ok(()) } + +const NOW_TIME: u64 = 10_000; +const WORKER_TIMEOUT: Duration = Duration::from_mins(2); +const MAX_EXECUTING: Duration = Duration::from_mins(15); + +fn make_system_time(add_time: u64) -> SystemTime { + SystemTime::UNIX_EPOCH + .checked_add(Duration::from_secs(NOW_TIME + add_time)) + .unwrap() +} + +/// An action already assigned to `worker_id` and executing since `started`. +fn executing_action(worker_id: &WorkerId, started: SystemTime) -> AwaitedAction { + let action_digest = DigestInfo::zero_digest(); + let action_info = ActionInfo { + command_digest: action_digest, + input_root_digest: action_digest, + timeout: Duration::ZERO, + platform_properties: HashMap::default(), + priority: 0, + load_timestamp: SystemTime::UNIX_EPOCH, + insert_timestamp: started, + unique_qualifier: ActionUniqueQualifier::Uncacheable(ActionUniqueKey { + instance_name: "main".to_string(), + digest_function: DigestHasherFunc::Sha256, + digest: action_digest, + }), + }; + let operation_id = OperationId::default(); + let mut action = AwaitedAction::new(operation_id.clone(), Arc::new(action_info), started); + action.worker_set_state( + Arc::new(ActionState { + stage: ActionStage::Executing, + client_operation_id: operation_id, + action_digest, + last_transition_timestamp: started, + }), + started, + ); + action.set_worker_id(Some(worker_id.clone()), started); + action +} + +fn state_manager( + registry: Arc, +) -> Arc< + SimpleSchedulerStateManager< + impl nativelink_scheduler::awaited_action_db::AwaitedActionDb, + MockInstantWrapped, + fn() -> MockInstantWrapped, + >, +> { + let task_change_notify = Arc::new(Notify::new()); + SimpleSchedulerStateManager::new( + 5, + WORKER_TIMEOUT, + Duration::from_mins(5), + MAX_EXECUTING, + memory_awaited_action_db_factory(0, &task_change_notify, MockInstantWrapped::default), + MockInstantWrapped::default, + Some(registry), + ) +} + +/// Same as above but with `max_action_executing_timeout_s` disabled, which is +/// its default. +fn state_manager_no_executing_ceiling( + registry: Arc, +) -> Arc< + SimpleSchedulerStateManager< + impl nativelink_scheduler::awaited_action_db::AwaitedActionDb, + MockInstantWrapped, + fn() -> MockInstantWrapped, + >, +> { + let task_change_notify = Arc::new(Notify::new()); + SimpleSchedulerStateManager::new( + 5, + WORKER_TIMEOUT, + Duration::from_mins(5), + Duration::ZERO, + memory_awaited_action_db_factory(0, &task_change_notify, MockInstantWrapped::default), + MockInstantWrapped::default, + Some(registry), + ) +} + +/// An orphan must still be reaped when `max_action_executing_timeout_s` is +/// disabled, which is its default. +/// +/// An HPA scaling a replica down leaves its workers' actions Executing in +/// shared state, naming worker ids no surviving instance recognises. If the +/// only ceiling for Unknown were the executing timeout, the default config +/// would never reap them and every scale-down would leak actions until the +/// client gave up. +#[nativelink_test] +async fn reaps_an_orphan_even_with_the_executing_ceiling_disabled() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let action = executing_action( + &WorkerId::from(String::from("owner-was-scaled-down")), + make_system_time(0), + ); + let state_mgr = state_manager_no_executing_ceiling(Arc::new(WorkerRegistry::new())); + + // Past worker_timeout_s: still must not fire, this could be a healthy + // action on a peer's worker. + MockClock::advance(WORKER_TIMEOUT + Duration::from_mins(1)); + assert!( + !state_mgr.should_timeout_operation(&action).await, + "must not reap at worker_timeout_s just because the ceiling is disabled" + ); + + // Past the orphan backstop: now it has to go, or it never will. + MockClock::advance(Duration::from_mins(61)); + assert!( + state_mgr.should_timeout_operation(&action).await, + "an orphan must be reaped by the backstop when no ceiling is configured" + ); + Ok(()) +} + +/// An action on a worker connected to a DIFFERENT scheduler instance must not +/// be timed out here. This instance never sees that worker's heartbeats, so +/// the action's timestamp looks frozen however healthy it is. +#[nativelink_test] +async fn does_not_time_out_a_peer_instances_worker() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + // Deliberately not registered here: it belongs to another instance. + let action = executing_action( + &WorkerId::from(String::from("owned-by-another-scheduler")), + make_system_time(0), + ); + let state_mgr = state_manager(Arc::new(WorkerRegistry::new())); + + MockClock::advance(WORKER_TIMEOUT + Duration::from_mins(1)); + assert!( + !state_mgr.should_timeout_operation(&action).await, + "must not time out an action on a peer instance's worker" + ); + Ok(()) +} + +/// A worker registered here that stopped heartbeating is ours and looks dead, +/// so the short timeout must still fire. +#[nativelink_test] +async fn still_times_out_our_own_dead_worker() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from(String::from("connected-to-us")); + let action = executing_action(&worker_id, make_system_time(0)); + + let registry = Arc::new(WorkerRegistry::new()); + registry + .register_worker(&worker_id, make_system_time(0)) + .await; + let state_mgr = state_manager(registry); + + MockClock::advance(WORKER_TIMEOUT + Duration::from_mins(1)); + assert!( + state_mgr.should_timeout_operation(&action).await, + "a registered worker that stopped heartbeating must time out" + ); + Ok(()) +} + +/// A registered, heartbeating worker is bounded only by the executing ceiling. +#[nativelink_test] +async fn does_not_time_out_a_live_worker_mid_action() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from(String::from("connected-to-us")); + let action = executing_action(&worker_id, make_system_time(0)); + + let elapsed = WORKER_TIMEOUT + Duration::from_mins(1); + let registry = Arc::new(WorkerRegistry::new()); + registry + .update_worker_heartbeat(&worker_id, make_system_time(elapsed.as_secs())) + .await; + let state_mgr = state_manager(registry); + + MockClock::advance(elapsed); + assert!( + !state_mgr.should_timeout_operation(&action).await, + "a heartbeating worker's action must survive past worker_timeout_s" + ); + Ok(()) +} + +/// A heartbeating worker stuck on one action past the executing ceiling must +/// still be timed out, which is what `max_action_executing_timeout_s` is for. +#[nativelink_test] +async fn times_out_a_live_but_stuck_worker() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from(String::from("alive-but-wedged")); + let action = executing_action(&worker_id, make_system_time(0)); + + let elapsed = MAX_EXECUTING + Duration::from_mins(1); + let registry = Arc::new(WorkerRegistry::new()); + registry + .update_worker_heartbeat(&worker_id, make_system_time(elapsed.as_secs())) + .await; + let state_mgr = state_manager(registry); + + MockClock::advance(elapsed); + assert!( + state_mgr.should_timeout_operation(&action).await, + "a worker stuck past max_action_executing_timeout_s must time out" + ); + Ok(()) +} + +/// An orphan whose owning instance died permanently still gets reaped, on the +/// longer ceiling. +#[nativelink_test] +async fn eventually_times_out_an_orphan() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let action = executing_action( + &WorkerId::from(String::from("owner-died-permanently")), + make_system_time(0), + ); + let state_mgr = state_manager(Arc::new(WorkerRegistry::new())); + + MockClock::advance(MAX_EXECUTING + Duration::from_mins(1)); + assert!( + state_mgr.should_timeout_operation(&action).await, + "an orphaned action must still be reaped on max_action_executing_timeout_s" + ); + Ok(()) +} diff --git a/nativelink-scheduler/tests/simple_scheduler_test.rs b/nativelink-scheduler/tests/simple_scheduler_test.rs index 697f9a4e2..6425f7e58 100644 --- a/nativelink-scheduler/tests/simple_scheduler_test.rs +++ b/nativelink-scheduler/tests/simple_scheduler_test.rs @@ -2427,8 +2427,8 @@ async fn action_timeout_is_enforced_backend_side_test() -> Result<(), Error> { let task_change_notify = Arc::new(Notify::new()); let state_mgr = SimpleSchedulerStateManager::new( /* max_job_retries */ 1, - /* no_event_action_timeout */ Duration::from_secs(60), - /* client_action_timeout */ Duration::from_secs(60), + /* no_event_action_timeout */ Duration::from_mins(1), + /* client_action_timeout */ Duration::from_mins(1), /* max_executing_timeout */ Duration::ZERO, memory_awaited_action_db_factory( 0, @@ -2789,3 +2789,417 @@ async fn logs_when_no_workers_match() -> Result<(), Error> { Ok(()) } + +/// Regression test: a finished operation whose client entry is dropped late +/// (e.g. evicted after the retain window) must not remove the +/// action-key entry claimed by a newer operation for the same action, +/// otherwise later requests stop deduplicating onto the live operation. +#[nativelink_test] +async fn late_client_drop_does_not_orphan_replacement_operation() -> Result<(), Error> { + const NO_EVENT_ACTION_TIMEOUT: Duration = Duration::from_mins(1); + + let task_change_notify = Arc::new(Notify::new()); + let awaited_action_db = memory_awaited_action_db_factory( + 0, // Use the default retain_completed_for_s (60s). + &task_change_notify, + MockInstantWrapped::default, + ); + let action_info = make_base_action_info(make_system_time(0), DigestInfo::new([99u8; 32], 512)); + + // Client 1 creates operation A for the action key. + let client1_id = OperationId::default(); + let subscriber1 = awaited_action_db + .add_action( + client1_id.clone(), + action_info.clone(), + NO_EVENT_ACTION_TIMEOUT, + ) + .await?; + let mut awaited_action_a = subscriber1.borrow().await?; + let operation_id_a = awaited_action_a.operation_id().clone(); + + // Operation A finishes, releasing its action-key entry. + let mut completed_state = awaited_action_a.state().as_ref().clone(); + completed_state.stage = ActionStage::Completed(ActionResult::default()); + awaited_action_a.worker_set_state(Arc::new(completed_state), make_system_time(1)); + awaited_action_db + .update_awaited_action(awaited_action_a) + .await?; + + // Let the client 1 entry go stale past the retain window without dropping + // the subscriber, mimicking a client that vanished without cleanup. + MockClock::advance(Duration::from_mins(2)); + + // Client 2 requests the same action; the key is free, so a new operation B + // claims it. Inserting client 2 also evicts the stale client 1 entry, + // queueing the ClientDroppedOperation cleanup for operation A. + let client2_id = OperationId::default(); + let subscriber2 = awaited_action_db + .add_action( + client2_id.clone(), + action_info.clone(), + NO_EVENT_ACTION_TIMEOUT, + ) + .await?; + let operation_id_b = subscriber2.borrow().await?.operation_id().clone(); + assert_ne!(operation_id_a, operation_id_b); + + // Let the background event task process client 1's drop. The cleanup of + // finished operation A must leave operation B's action-key entry alone. + for _ in 0..10 { + tokio::task::yield_now().await; + } + + // Client 3 requesting the same action must join operation B instead of + // creating a third operation. + let client3_id = OperationId::default(); + let subscriber3 = awaited_action_db + .add_action(client3_id.clone(), action_info, NO_EVENT_ACTION_TIMEOUT) + .await?; + let operation_id_c = subscriber3.borrow().await?.operation_id().clone(); + assert_eq!(operation_id_b, operation_id_c); + + assert!(!logs_contain("out of sync")); + assert!(!logs_contain("should have had the unique_key")); + + Ok(()) +} + +/// Wraps a real `AwaitedActionDb`, but hides queued actions from +/// `get_range_of_actions` while `suppress_queued_searches` is set. This +/// simulates an eventually consistent backend (e.g. Redis), where a +/// (re-)queued operation may not yet be visible to the search that its own +/// change notification triggered. +#[derive(MetricsComponent)] +struct QueuedSearchSuppressingDb { + inner: A, + suppress_queued_searches: Arc, +} + +impl AwaitedActionDb for QueuedSearchSuppressingDb { + type Subscriber = A::Subscriber; + + async fn get_awaited_action_by_id( + &self, + client_operation_id: &OperationId, + ) -> Result, Error> { + self.inner + .get_awaited_action_by_id(client_operation_id) + .await + } + + async fn get_all_awaited_actions( + &self, + ) -> Result> + Send, Error> { + self.inner.get_all_awaited_actions().await + } + + async fn get_by_operation_id( + &self, + operation_id: &OperationId, + ) -> Result, Error> { + self.inner.get_by_operation_id(operation_id).await + } + + async fn get_range_of_actions( + &self, + state: SortedAwaitedActionState, + start: Bound, + end: Bound, + desc: bool, + ) -> Result> + Send, Error> { + let items = if matches!(state, SortedAwaitedActionState::Queued) + && self.suppress_queued_searches.load(Ordering::Acquire) + { + Vec::new() + } else { + self.inner + .get_range_of_actions(state, start, end, desc) + .await? + .collect::>() + .await + }; + Ok(futures::stream::iter(items)) + } + + async fn update_awaited_action(&self, new_awaited_action: AwaitedAction) -> Result<(), Error> { + self.inner.update_awaited_action(new_awaited_action).await + } + + async fn add_action( + &self, + client_operation_id: OperationId, + action_info: Arc, + no_event_action_timeout: Duration, + ) -> Result { + self.inner + .add_action(client_operation_id, action_info, no_event_action_timeout) + .await + } +} + +/// Common setup for the fallback match interval tests: a scheduler over a +/// `QueuedSearchSuppressingDb` with a channel that receives a message after +/// every completed matching pass. +type FallbackTestSetup = ( + Arc, + Arc, + Arc, + mpsc::UnboundedReceiver<()>, +); + +fn make_fallback_test_scheduler(fallback_match_interval_s: i64) -> FallbackTestSetup { + let task_change_notify = Arc::new(Notify::new()); + let suppress_queued_searches = Arc::new(AtomicBool::new(false)); + let (match_tx, match_rx) = mpsc::unbounded_channel(); + let (scheduler, _worker_scheduler) = SimpleScheduler::new_with_callback( + &SimpleSpec { + fallback_match_interval_s, + ..Default::default() + }, + QueuedSearchSuppressingDb { + inner: memory_awaited_action_db_factory( + 0, + &task_change_notify.clone(), + MockInstantWrapped::default, + ), + suppress_queued_searches: suppress_queued_searches.clone(), + }, + move || { + let match_tx = match_tx.clone(); + async move { + let _ = match_tx.send(()); + } + }, + task_change_notify.clone(), + MockInstantWrapped::default, + None, + ); + ( + scheduler, + task_change_notify, + suppress_queued_searches, + match_rx, + ) +} + +/// Waits until no matching pass has completed for a short while, which +/// guarantees no notification permits are pending and no pass is in flight. +async fn wait_for_matching_passes_to_settle(match_rx: &mut mpsc::UnboundedReceiver<()>) { + while tokio::time::timeout(Duration::from_millis(200), match_rx.recv()) + .await + .is_ok() + {} +} + +// Regression test for a queued operation not being visible to the matching +// engine search that its own change notification triggered (e.g. an OOM-killed +// worker's operation being re-queued while the Redis search index is stale). +// The fallback match interval must rescue such an operation. +#[nativelink_test(start_paused = true)] +async fn fallback_match_interval_rescues_action_hidden_from_search() -> Result<(), Error> { + let worker_id = WorkerId("worker_id".to_string()); + let (scheduler, _task_change_notify, suppress_queued_searches, mut match_rx) = + make_fallback_test_scheduler(1 /* fallback_match_interval_s */); + let action_digest = DigestInfo::new([99u8; 32], 512); + + let mut rx_from_worker = + setup_new_worker(&scheduler, worker_id.clone(), PlatformProperties::default()).await?; + + // Hide the action from the matching engine's queued searches, then add it. + suppress_queued_searches.store(true, Ordering::Release); + let insert_timestamp = make_system_time(1); + let mut action_listener = + setup_action(&scheduler, action_digest, HashMap::new(), insert_timestamp).await?; + + wait_for_matching_passes_to_settle(&mut match_rx).await; + + // All notification-triggered passes ran while the action was hidden, so + // nothing was assigned to the worker. + assert_eq!(poll!(Box::pin(rx_from_worker.recv())), Poll::Pending); + + // Make the action visible again. No notification fires for this, so only + // the fallback match interval can rescue the action now. + suppress_queued_searches.store(false, Ordering::Release); + + let msg_for_worker = tokio::time::timeout(Duration::from_secs(30), rx_from_worker.recv()) + .await + .expect("Fallback matching pass should have assigned the action") + .unwrap(); + match msg_for_worker.update { + Some(update_for_worker::Update::StartAction(start_execute)) => { + assert_eq!( + start_execute.execute_request.unwrap().action_digest, + Some(action_digest.into()) + ); + } + other => panic!("Expected StartAction, got: {other:?}"), + } + + // Client should see the action executing. + let (action_state, _maybe_origin_metadata) = action_listener.changed().await.unwrap(); + assert_eq!(action_state.stage, ActionStage::Executing); + + Ok(()) +} + +// With the fallback match interval disabled, the same scenario leaves the +// action stuck in the queued state until an unrelated event triggers another +// matching pass. This documents the behavior the fallback interval fixes. +#[nativelink_test(start_paused = true)] +async fn fallback_match_interval_disabled_leaves_hidden_action_queued() -> Result<(), Error> { + let worker_id = WorkerId("worker_id".to_string()); + let (scheduler, task_change_notify, suppress_queued_searches, mut match_rx) = + make_fallback_test_scheduler(-1 /* fallback_match_interval_s */); + let action_digest = DigestInfo::new([99u8; 32], 512); + + let mut rx_from_worker = + setup_new_worker(&scheduler, worker_id.clone(), PlatformProperties::default()).await?; + + // Hide the action from the matching engine's queued searches, then add it. + suppress_queued_searches.store(true, Ordering::Release); + let insert_timestamp = make_system_time(1); + let _action_listener = + setup_action(&scheduler, action_digest, HashMap::new(), insert_timestamp).await?; + + wait_for_matching_passes_to_settle(&mut match_rx).await; + suppress_queued_searches.store(false, Ordering::Release); + + // Without the fallback interval nothing ever rescues the action. + assert!( + tokio::time::timeout(Duration::from_secs(30), rx_from_worker.recv()) + .await + .is_err(), + "Action should stay queued with the fallback match interval disabled" + ); + + // Only an unrelated task change event triggers another matching pass. + task_change_notify.notify_one(); + let msg_for_worker = tokio::time::timeout(Duration::from_secs(5), rx_from_worker.recv()) + .await + .expect("Task change notification should have assigned the action") + .unwrap(); + assert!(matches!( + msg_for_worker.update, + Some(update_for_worker::Update::StartAction(_)) + )); + + Ok(()) +} + +/// Regression test: when the worker reports an action finished but the +/// state-manager update fails because the operation was already completed +/// (e.g. the client-timeout sweep marked it `DeadlineExceeded` while the +/// worker was still executing it), the worker's platform properties must +/// still be restored. They used to leak, permanently shrinking the worker's +/// capacity until no action could match it. +#[nativelink_test] +async fn failed_final_update_does_not_leak_worker_capacity() -> Result<(), Error> { + let worker_id = WorkerId("worker_id".to_string()); + + let task_change_notify = Arc::new(Notify::new()); + let (scheduler, _worker_scheduler) = SimpleScheduler::new_with_callback( + &SimpleSpec { + supported_platform_properties: Some(HashMap::from([( + "cpu_count".to_string(), + PropertyType::Minimum, + )])), + ..Default::default() + }, + memory_awaited_action_db_factory( + // Large retain window so the stale client entry is not evicted: + // the operation must still exist (as finished) when the worker + // reports, since a missing operation is tolerated by the state + // manager and would not reproduce the leak. + 100_000, + &task_change_notify.clone(), + MockInstantWrapped::default, + ), + || async move {}, + task_change_notify, + MockInstantWrapped::default, + None, + ); + + // The worker has a single cpu slot, so one leaked slot is enough to make + // it unmatchable. + let mut rx_from_worker = setup_new_worker( + &scheduler, + worker_id.clone(), + PlatformProperties::new(HashMap::from([( + "cpu_count".to_string(), + PlatformPropertyValue::Minimum(1), + )])), + ) + .await?; + + let platform_properties = HashMap::from([("cpu_count".to_string(), "1".to_string())]); + + // Action 1 is assigned to the worker, consuming the only slot. + let _action1_listener = setup_action( + &scheduler, + DigestInfo::new([1u8; 32], 512), + platform_properties.clone(), + make_system_time(1), + ) + .await?; + let operation_id = match rx_from_worker.recv().await.unwrap().update { + Some(update_for_worker::Update::StartAction(start_execute)) => start_execute.operation_id, + v => panic!("Expected StartAction, got : {v:?}"), + }; + + // The client stops sending keepalives past client_action_timeout_s, then + // a sweep over all operations times the executing operation out, marking + // it Completed(DeadlineExceeded) while the worker still runs it. + MockClock::advance(Duration::from_mins(2)); + drop( + scheduler + .filter_operations(OperationFilter::default()) + .await? + .collect::>() + .await, + ); + assert!(logs_contain( + "Operation timed out having no more clients listening" + )); + + // Action 2 queues: the worker's only slot is still held by action 1. + let _action2_listener = setup_action( + &scheduler, + DigestInfo::new([2u8; 32], 512), + platform_properties, + make_system_time(2), + ) + .await?; + + // The worker now reports action 1 finished. The state-manager update + // fails ("already completed"), but the worker's slot must still be freed. + let update_result = scheduler + .update_action( + &worker_id, + &OperationId::from(operation_id), + UpdateOperationType::UpdateWithActionStage(ActionStage::Completed( + ActionResult::default(), + )), + ) + .await; + assert_eq!( + update_result + .expect_err("state-manager update should fail") + .code, + Code::Internal + ); + + // With the slot restored, action 2 must get matched to the worker. + scheduler.do_try_match_for_test().await?; + match rx_from_worker + .try_recv() + .expect("worker should have been sent action 2") + .update + { + Some(update_for_worker::Update::StartAction(_)) => {} + v => panic!("Expected StartAction for the second action, got : {v:?}"), + } + + Ok(()) +} diff --git a/nativelink-scheduler/tests/store_awaited_action_db_test.rs b/nativelink-scheduler/tests/store_awaited_action_db_test.rs index 3f2e6ffe4..5f8c3429a 100644 --- a/nativelink-scheduler/tests/store_awaited_action_db_test.rs +++ b/nativelink-scheduler/tests/store_awaited_action_db_test.rs @@ -8,15 +8,16 @@ use std::time::SystemTime; use bytes::Bytes; use futures::{Stream, stream}; -use mock_instant::thread_local::SystemTime as MockSystemTime; +use mock_instant::thread_local::{MockClock, SystemTime as MockSystemTime}; use nativelink_error::Error; use nativelink_macro::nativelink_test; -use nativelink_scheduler::awaited_action_db::AwaitedAction; +use nativelink_scheduler::awaited_action_db::{AwaitedAction, AwaitedActionDb}; use nativelink_scheduler::store_awaited_action_db::{ StoreAwaitedActionDb, inner_update_awaited_action, }; +use nativelink_scheduler::worker_registry::{ORPHANED_ACTION_TIMEOUT, WorkerRegistry}; use nativelink_util::action_messages::{ - ActionInfo, ActionUniqueKey, ActionUniqueQualifier, OperationId, + ActionInfo, ActionStage, ActionUniqueKey, ActionUniqueQualifier, OperationId, WorkerId, }; use nativelink_util::common::DigestInfo; use nativelink_util::digest_hasher::DigestHasherFunc; @@ -309,7 +310,7 @@ async fn try_subscribe_retries_once_on_miss_then_returns_existing() -> Result<() .try_subscribe( &OperationId::from("client-1"), &qualifier, - Duration::from_secs(60), + Duration::from_mins(1), 0, ) .await?; @@ -341,7 +342,7 @@ async fn try_subscribe_returns_none_after_two_consecutive_misses() -> Result<(), .try_subscribe( &OperationId::from("client-2"), &qualifier, - Duration::from_secs(60), + Duration::from_mins(1), 0, ) .await?; @@ -376,7 +377,7 @@ async fn try_subscribe_skips_lookup_for_uncacheable_qualifier() -> Result<(), Er .try_subscribe( &OperationId::from("client-3"), &uncacheable, - Duration::from_secs(60), + Duration::from_mins(1), 0, ) .await?; @@ -389,3 +390,170 @@ async fn try_subscribe_skips_lookup_for_uncacheable_qualifier() -> Result<(), Er ); Ok(()) } + +// --------------------------------------------------------------------------- +// `try_subscribe` abandonment check. +// +// The stage/timestamp pair lives in the shared store and heartbeats never +// refresh it, so without a liveness check a healthy long-running action looks +// abandoned and a duplicate Execute forks a second execution of it. +// --------------------------------------------------------------------------- + +const WORKER_TIMEOUT: Duration = Duration::from_mins(2); +const NOW_TIME: u64 = 10_000; + +/// `MockInstantWrapped::now` reads `MockClock::time`, so timestamps have to be +/// built from the same clock or nothing lines up. +fn mock_now() -> SystemTime { + SystemTime::UNIX_EPOCH + MockClock::time() +} + +fn make_executing_awaited_action(worker_id: &WorkerId) -> AwaitedAction { + let now = mock_now(); + let mut action = AwaitedAction::new( + OperationId::from("existing-operation"), + make_cacheable_action_info(), + now, + ); + action.set_worker_id(Some(worker_id.clone()), now); + let mut state = action.state().as_ref().clone(); + state.stage = ActionStage::Executing; + action.worker_set_state(Arc::new(state), now); + action +} + +/// Runs `try_subscribe` against an executing action owned by `worker_id`, +/// after `elapsed` has passed, and reports whether the action was recreated +/// rather than joined. +async fn recreated_after( + registry: Option>, + worker_id: &WorkerId, + elapsed: Duration, +) -> Result { + let action = make_executing_awaited_action(worker_id); + let qualifier = action.action_info().unique_qualifier.clone(); + let store = Arc::new(EventuallyVisibleStore::new( + /* empty_for = */ 0, &action, + )); + let mut db = build_db(store).await; + if let Some(registry) = registry { + db.set_worker_registry(registry); + } + + MockClock::advance(elapsed); + + let result = db + .try_subscribe( + &OperationId::from("client-abandon"), + &qualifier, + WORKER_TIMEOUT, + 0, + ) + .await? + .expect("the action is visible, so try_subscribe must return it"); + + Ok(*result.operation_id() == OperationId::from("new-operation")) +} + +#[nativelink_test] +async fn joins_an_executing_action_whose_worker_is_ours_and_alive() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from("worker-alive".to_string()); + let registry = Arc::new(WorkerRegistry::new()); + + // Heartbeats keep the registry current even though the shared timestamp + // on the action does not move. + let action = make_executing_awaited_action(&worker_id); + let qualifier = action.action_info().unique_qualifier.clone(); + let store = Arc::new(EventuallyVisibleStore::new( + /* empty_for = */ 0, &action, + )); + let mut db = build_db(store).await; + db.set_worker_registry(registry.clone()); + + // The action's shared timestamp stays put while the worker keeps + // heartbeating, which is exactly the case that used to look abandoned. + MockClock::advance(WORKER_TIMEOUT * 3); + registry + .update_worker_heartbeat(&worker_id, mock_now()) + .await; + + let result = db + .try_subscribe( + &OperationId::from("client-alive"), + &qualifier, + WORKER_TIMEOUT, + 0, + ) + .await? + .expect("action is visible"); + let recreated = *result.operation_id() == OperationId::from("new-operation"); + + assert!( + !recreated, + "a worker we can see heartbeating owns this action; recreating it would run the work twice", + ); + Ok(()) +} + +#[nativelink_test] +async fn recreates_an_executing_action_whose_worker_went_quiet() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from("worker-stale".to_string()); + let registry = Arc::new(WorkerRegistry::new()); + registry.register_worker(&worker_id, mock_now()).await; + + let recreated = recreated_after(Some(registry), &worker_id, WORKER_TIMEOUT * 2).await?; + + assert!( + recreated, + "the worker is registered here and has stopped reporting, so the action is genuinely abandoned", + ); + Ok(()) +} + +#[nativelink_test] +async fn joins_an_executing_action_on_a_peers_worker() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from("worker-elsewhere".to_string()); + // Empty registry: the worker belongs to another scheduler instance. + let registry = Arc::new(WorkerRegistry::new()); + + let recreated = recreated_after(Some(registry), &worker_id, WORKER_TIMEOUT * 5).await?; + + assert!( + !recreated, + "worker_timeout_s must not apply to a worker this instance never sees heartbeats for", + ); + Ok(()) +} + +#[nativelink_test] +async fn recreates_an_orphan_once_past_the_backstop() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from("worker-orphaned".to_string()); + let registry = Arc::new(WorkerRegistry::new()); + + let recreated = + recreated_after(Some(registry), &worker_id, ORPHANED_ACTION_TIMEOUT * 2).await?; + + assert!( + recreated, + "an action nobody claims still has to be reaped eventually or it leaks forever", + ); + Ok(()) +} + +#[nativelink_test] +async fn falls_back_to_the_timestamp_when_there_is_no_registry() -> Result<(), Error> { + MockClock::set_time(Duration::from_secs(NOW_TIME)); + let worker_id = WorkerId::from("worker-no-registry".to_string()); + + let recreated = recreated_after(None, &worker_id, WORKER_TIMEOUT * 2).await?; + + assert!( + recreated, + "without a registry there is nothing better than the timestamp, so behaviour is unchanged", + ); + Ok(()) +} diff --git a/nativelink-scheduler/tests/worker_registry_test.rs b/nativelink-scheduler/tests/worker_registry_test.rs index 50328b2ba..69b870187 100644 --- a/nativelink-scheduler/tests/worker_registry_test.rs +++ b/nativelink-scheduler/tests/worker_registry_test.rs @@ -30,8 +30,11 @@ async fn is_worker_alive_logging() -> Result<(), Error> { .is_worker_alive(&worker_id, Duration::from_secs(10), SystemTime::UNIX_EPOCH) .await ); + // `liveness` replaced the old `is_alive` bool: a two-state field could not + // express "not registered on this instance", which is what made + // multi-scheduler deployments time each other's actions out. assert!(logs_contain( - "FLOW: Worker liveness check worker_id=foo last_seen=1970-01-01T00:00:00Z timeout=10s is_alive=true" + "FLOW: Worker liveness check worker_id=foo last_seen=1970-01-01T00:00:00Z timeout=10s liveness=Alive" )); Ok(()) } diff --git a/nativelink-service/BUILD.bazel b/nativelink-service/BUILD.bazel index 5015732e0..72b9cbd8f 100644 --- a/nativelink-service/BUILD.bazel +++ b/nativelink-service/BUILD.bazel @@ -21,6 +21,7 @@ rust_library( "src/lib.rs", "src/push_server.rs", "src/remote_asset_proto.rs", + "src/wire_compression.rs", "src/worker_api_server.rs", ], visibility = ["//visibility:public"], @@ -34,6 +35,7 @@ rust_library( "//nativelink-util", "@crates//:axum", "@crates//:bytes", + "@crates//:fastcdc", "@crates//:futures", "@crates//:http-body-util", "@crates//:hyper-1.7.0", @@ -46,10 +48,12 @@ rust_library( "@crates//:serde_json5", "@crates//:sha2", "@crates//:tokio", + "@crates//:tokio-util", "@crates//:tonic", "@crates//:tower", "@crates//:tracing", "@crates//:uuid", + "@crates//:zstd", ], ) @@ -60,13 +64,20 @@ rust_test_suite( "tests/ac_server_test.rs", "tests/bep_server_test.rs", "tests/bytestream_server_test.rs", + "tests/capabilities_server_test.rs", "tests/cas_server_test.rs", "tests/execution_server_test.rs", + "tests/fastcdc_conformance_test.rs", "tests/fetch_server_test.rs", + "tests/grpc_wire_compression_test.rs", "tests/health_server_test.rs", "tests/push_server_test.rs", + "tests/wire_compression_test.rs", "tests/worker_api_server_test.rs", ], + compile_data = glob(["tests/data/**"]) + [ + "//nativelink-util:tests/data/SekienAkashita.jpg", + ], proc_macro_deps = [ "//nativelink-macro", "@crates//:async-trait", @@ -83,6 +94,7 @@ rust_test_suite( "@crates//:async-lock", "@crates//:axum", "@crates//:bytes", + "@crates//:fastcdc", "@crates//:futures", "@crates//:hex", "@crates//:http-body-util", @@ -96,9 +108,11 @@ rust_test_suite( "@crates//:tokio", "@crates//:tokio-stream", "@crates//:tonic", + "@crates//:tonic-prost", "@crates//:tower", "@crates//:tracing", "@crates//:tracing-test", + "@crates//:zstd", ], ) diff --git a/nativelink-service/Cargo.toml b/nativelink-service/Cargo.toml index 2fadad6d2..b067028e8 100644 --- a/nativelink-service/Cargo.toml +++ b/nativelink-service/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-service" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-config = { path = "../nativelink-config" } @@ -17,17 +17,18 @@ nativelink-util = { path = "../nativelink-util" } axum = { version = "0.8.3", default-features = false } bytes = { version = "1.10.1", default-features = false } +fastcdc = { version = "3.2.1", default-features = false, features = ["tokio"] } futures = { version = "0.3.31", default-features = false } http-body-util = { version = "0.1.3", default-features = false } hyper = { version = "1.6.0", default-features = false } -opentelemetry = { version = "0.30.0", default-features = false } -opentelemetry-semantic-conventions = { version = "0.30.0", default-features = false, features = [ +opentelemetry = { version = "0.32.0", default-features = false } +opentelemetry-semantic-conventions = { version = "0.32.0", default-features = false, features = [ "default", "semconv_experimental", ] } parking_lot = { version = "0.12.3", default-features = false } -prost = { version = "0.13.5", default-features = false } -prost-types = { version = "0.13.5", default-features = false, features = [ +prost = { version = "0.14.4", default-features = false } +prost-types = { version = "0.14.4", default-features = false, features = [ "std", ] } rand = { version = "0.9.0", default-features = false, features = [ @@ -43,7 +44,8 @@ tokio = { version = "1.52.2", features = [ tokio-stream = { version = "0.1.17", features = [ "fs", ], default-features = false } -tonic = { version = "0.13.0", features = [ +tokio-util = { version = "0.7.14", features = ["io"], default-features = false } +tonic = { version = "0.14.0", features = [ "gzip", "router", "tls-ring", @@ -55,6 +57,7 @@ uuid = { version = "1.16.0", default-features = false, features = [ "serde", "v4", ] } +zstd = { version = "0.13.3", default-features = false } [dev-dependencies] nativelink-macro = { path = "../nativelink-macro" } @@ -67,7 +70,6 @@ hyper-util = { version = "0.1.11", default-features = false } pretty_assertions = { version = "1.4.1", features = [ "std", ], default-features = false } -prost-types = { version = "0.13.5", default-features = false } serde_json = { version = "1.0.140", default-features = false, features = [ "std", ] } @@ -75,6 +77,7 @@ sha2 = { version = "0.10.8", default-features = false } tokio = { version = "1.52.2", features = [ "test-util", ], default-features = false } +tonic-prost = { version = "0.14.6", default-features = false } tracing-test = { version = "0.2.5", default-features = false, features = [ "no-env-filter", ] } diff --git a/nativelink-service/src/bytestream_server.rs b/nativelink-service/src/bytestream_server.rs index 50671a3f6..179abe29b 100644 --- a/nativelink-service/src/bytestream_server.rs +++ b/nativelink-service/src/bytestream_server.rs @@ -17,8 +17,8 @@ use core::fmt::{Debug, Formatter}; use core::pin::Pin; use core::sync::atomic::{AtomicU64, Ordering}; use core::time::Duration; -use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; use std::sync::Arc; use std::time::{Instant, SystemTime, UNIX_EPOCH}; @@ -31,6 +31,7 @@ use nativelink_error::{Code, Error, ResultExt, make_err, make_input_err}; use nativelink_metric::{ MetricFieldData, MetricKind, MetricPublishKnownKindData, MetricsComponent, group, publish, }; +use nativelink_proto::build::bazel::remote::execution::v2::compressor; use nativelink_proto::google::bytestream::byte_stream_server::{ ByteStream, ByteStreamServer as Server, }; @@ -58,6 +59,8 @@ use tokio::time::sleep; use tonic::{Request, Response, Status, Streaming}; use tracing::{Instrument, Level, debug, error, error_span, info, instrument, trace, warn}; +use crate::wire_compression::RemoteCacheCompressionInstances; + /// If this value changes update the documentation in the config definition. const DEFAULT_PERSIST_STREAM_ON_DISCONNECT_TIMEOUT: Duration = Duration::from_mins(1); @@ -254,6 +257,8 @@ pub struct InstanceInfo { metrics: Arc, /// Handle to the global sweeper task. Kept alive for the lifetime of the instance. _sweeper_handle: Arc>, + /// Whether this instance supports Bazel remote cache compression. + remote_cache_compression_enabled: bool, } impl Debug for InstanceInfo { @@ -264,10 +269,128 @@ impl Debug for InstanceInfo { .field("active_uploads", &self.active_uploads) .field("idle_stream_timeout", &self.idle_stream_timeout) .field("metrics", &self.metrics) + .field( + "remote_cache_compression_enabled", + &self.remote_cache_compression_enabled, + ) .finish() } } +struct CompressedUploadGuard { + uuid_key: u128, + active_uploads: Arc>>, + metrics: Arc, +} + +impl Drop for CompressedUploadGuard { + fn drop(&mut self) { + self.active_uploads.lock().remove(&self.uuid_key); + self.metrics.active_uploads.fetch_sub(1, Ordering::Relaxed); + } +} + +impl InstanceInfo { + fn track_compressed_upload( + &self, + uuid_key: UuidKey, + ) -> (Arc, CompressedUploadGuard) { + let bytes_received = Arc::new(AtomicU64::new(0)); + let uuid_key = { + let mut active_uploads = self.active_uploads.lock(); + match active_uploads.entry(uuid_key) { + Entry::Occupied(entry) => { + // Another upload already owns this UUID; rekey instead of + // clobbering its entry (which would break its QueryWriteStatus + // visibility and double-decrement the metric on guard drop). + // Mirrors create_or_join_upload_stream's collision handling. + let original_key = *entry.key(); + let unique_key = ByteStreamServer::generate_unique_uuid_key(original_key); + warn!( + msg = "UUID collision detected on compressed upload, generating unique UUID to prevent conflict", + original_uuid = format!("{original_key:032x}"), + unique_uuid = format!("{unique_key:032x}") + ); + self.metrics.uuid_collisions.fetch_add(1, Ordering::Relaxed); + // Release the Occupied entry's borrow so we can insert on the same guard. + let _ = entry; + active_uploads.insert(unique_key, (bytes_received.clone(), None)); + unique_key + } + Entry::Vacant(entry) => { + let key = *entry.key(); + entry.insert((bytes_received.clone(), None)); + key + } + } + }; + self.metrics.active_uploads.fetch_add(1, Ordering::Relaxed); + + ( + bytes_received, + CompressedUploadGuard { + uuid_key, + active_uploads: self.active_uploads.clone(), + metrics: self.metrics.clone(), + }, + ) + } +} + +/// Pump compressed `ByteStream` upload chunks into the decoder. +/// +/// Compressed uploads intentionally do not support the identity upload resume +/// protocol; offsets are validated against compressed wire bytes. +async fn process_compressed_client_stream( + mut stream: WriteRequestStreamWrapper> + Unpin>, + mut tx: DropCloserWriteHalf, + bytes_received: &Arc, +) -> Result<(), Error> { + loop { + match stream.next().await { + Some(Ok(write_request)) => { + if write_request.write_offset < 0 { + return Err(make_input_err!( + "Invalid negative compressed write offset in write request: {}", + write_request.write_offset + )); + } + let write_offset = u64::try_from(write_request.write_offset) + .err_tip(|| "Compressed write offset was not convertible to u64")?; + let compressed_offset = tx.get_bytes_written(); + if write_offset != compressed_offset { + return Err(make_input_err!( + "Received out of order compressed data. Got {}, expected {}", + write_offset, + compressed_offset + )); + } + + if !write_request.data.is_empty() { + tx.send(write_request.data) + .await + .err_tip(|| "Failed to forward compressed upload data")?; + bytes_received.store(tx.get_bytes_written(), Ordering::Release); + } + if write_request.finish_write { + tx.send_eof() + .err_tip(|| "Failed to send compressed upload EOF")?; + return Ok(()); + } + } + Some(Err(e)) => { + return Err(e); + } + None => { + return Err(make_err!( + Code::InvalidArgument, + "Compressed write stream ended without finish_write" + )); + } + } + } +} + type ReadStream = Pin> + Send + 'static>>; type StoreUpdateFuture = Pin> + Send + 'static>>; @@ -275,6 +398,7 @@ struct StreamState { uuid: UuidKey, tx: DropCloserWriteHalf, store_update_fut: StoreUpdateFuture, + digest_function: DigestHasherFunc, } impl Debug for StreamState { @@ -358,6 +482,7 @@ impl IdleStream { #[derive(Debug)] pub struct ByteStreamServer { instance_infos: HashMap, + reported_digest_function_mismatches: Mutex>, } impl ByteStreamServer { @@ -375,6 +500,7 @@ impl ByteStreamServer { pub fn new( configs: &[WithInstanceName], store_manager: &StoreManager, + remote_cache_compression_instances: &RemoteCacheCompressionInstances, ) -> Result { let mut instance_infos: HashMap = HashMap::new(); for config in configs { @@ -383,18 +509,29 @@ impl ByteStreamServer { } else { Duration::from_secs(config.persist_stream_on_disconnect_timeout_s as u64) }; + let remote_cache_compression_enabled = + remote_cache_compression_instances.enabled_for(&config.instance_name); let _old_value = instance_infos.insert( config.instance_name.clone(), - Self::new_with_timeout(config, store_manager, idle_stream_timeout)?, + Self::new_with_timeout( + config, + store_manager, + idle_stream_timeout, + remote_cache_compression_enabled, + )?, ); } - Ok(Self { instance_infos }) + Ok(Self { + instance_infos, + reported_digest_function_mismatches: Mutex::new(HashSet::new()), + }) } pub fn new_with_timeout( config: &WithInstanceName, store_manager: &StoreManager, idle_stream_timeout: Duration, + remote_cache_compression_enabled: bool, ) -> Result { let store = store_manager .get_store(&config.cas_store) @@ -467,6 +604,7 @@ impl ByteStreamServer { idle_stream_timeout, metrics, _sweeper_handle: Arc::new(sweeper_handle), + remote_cache_compression_enabled, }) } @@ -490,7 +628,13 @@ impl ByteStreamServer { uuid_str: &str, instance: &InstanceInfo, digest: DigestInfo, - ) -> ActiveStreamGuard { + digest_function: DigestHasherFunc, + ) -> Result { + // Bind the digest function to the retained store future itself. The + // future can outlive this RPC while an upload is idle, so it must not + // depend on the context of whichever request polls it next. + let store_update_context = make_ctx_for_hash_func(digest_function)?; + // Parse UUID string to u128 key for efficient HashMap operations let uuid_key = parse_uuid_to_key(uuid_str); @@ -499,6 +643,15 @@ impl ByteStreamServer { match active_uploads.entry(uuid_key) { Entry::Occupied(mut entry) => { let maybe_idle_stream = entry.get_mut(); + if let Some(idle_stream) = maybe_idle_stream.1.as_ref() + && idle_stream.stream_state.digest_function != digest_function + { + return Err(make_input_err!( + "Cannot resume upload with digest function {} because it started with {}", + digest_function, + idle_stream.stream_state.digest_function, + )); + } if let Some(idle_stream) = maybe_idle_stream.1.take() { // Case 2: Stream exists but is idle, we can resume it let bytes_received = maybe_idle_stream.0.clone(); @@ -511,7 +664,7 @@ impl ByteStreamServer { .metrics .resumed_uploads .fetch_add(1, Ordering::Relaxed); - return idle_stream.into_active_stream(bytes_received, instance); + return Ok(idle_stream.into_active_stream(bytes_received, instance)); } // Case 3: Stream is active - generate a unique UUID to avoid collision. // Using nanosecond timestamp makes collision probability essentially zero. @@ -523,7 +676,7 @@ impl ByteStreamServer { unique_uuid = format!("{:032x}", unique_key) ); // Release the Occupied entry's borrow so we can insert on the same guard. - drop(entry); + let _ = entry; let bytes_received = Arc::new(AtomicU64::new(0)); active_uploads.insert(unique_key, (bytes_received.clone(), None)); (unique_key, bytes_received, true) @@ -557,25 +710,29 @@ impl ByteStreamServer { let (tx, rx) = make_buf_channel_pair(); let store = instance.store.clone(); - let store_update_fut = Box::pin(async move { - // We need to wrap `Store::update()` in a another future because we need to capture - // `store` to ensure its lifetime follows the future and not the caller. - store - // Bytestream always uses digest size as the actual byte size. - .update(digest, rx, UploadSizeInfo::ExactSize(digest.size_bytes())) - .await - .map(|_| ()) - }); - ActiveStreamGuard { + let store_update_fut = Box::pin( + async move { + // We need to wrap `Store::update()` in a another future because we need to capture + // `store` to ensure its lifetime follows the future and not the caller. + store + // Bytestream always uses digest size as the actual byte size. + .update(digest, rx, UploadSizeInfo::ExactSize(digest.size_bytes())) + .await + .map(|_| ()) + } + .with_context(store_update_context), + ); + Ok(ActiveStreamGuard { stream_state: Some(StreamState { uuid, tx, store_update_fut, + digest_function, }), bytes_received, active_uploads: instance.active_uploads.clone(), metrics: instance.metrics.clone(), - } + }) } async fn inner_read( @@ -707,6 +864,7 @@ impl ByteStreamServer { &self, instance_info: &InstanceInfo, digest: DigestInfo, + digest_function: DigestHasherFunc, stream: WriteRequestStreamWrapper> + Unpin>, ) -> Result, Error> { async fn process_client_stream( @@ -802,7 +960,7 @@ impl ByteStreamServer { .as_ref() .ok_or_else(|| make_input_err!("UUID must be set if writing data"))?; let mut active_stream_guard = - self.create_or_join_upload_stream(uuid, instance_info, digest); + self.create_or_join_upload_stream(uuid, instance_info, digest, digest_function)?; let expected_size = stream.resource_info.expected_size as u64; let active_stream = active_stream_guard.stream_state.as_mut().unwrap(); @@ -821,7 +979,7 @@ impl ByteStreamServer { active_stream_guard.graceful_finish(); Ok(Response::new(WriteResponse { - committed_size: expected_size as i64, + committed_size: expected_size.try_into().unwrap_or(i64::MAX), })) } @@ -831,6 +989,7 @@ impl ByteStreamServer { &self, instance_info: &InstanceInfo, digest: DigestInfo, + digest_function: DigestHasherFunc, mut stream: WriteRequestStreamWrapper< impl Stream> + Unpin, >, @@ -905,18 +1064,257 @@ impl ByteStreamServer { // Direct update without channel overhead let store = instance_info.store.clone(); + let store_update_context = make_ctx_for_hash_func(digest_function)?; store .update_oneshot(digest, buffer.freeze()) + .with_context(store_update_context) .await .err_tip(|| "Error in update_oneshot")?; // Note: bytes_written_total is updated in the caller (bytestream_write) based on result Ok(Response::new(WriteResponse { - committed_size: expected_size as i64, + committed_size: expected_size.try_into().unwrap_or(i64::MAX), })) } + /// Handle a compressed upload: stream compressed wire bytes through the + /// decoder into the store update stream, validate the decoded size, and + /// verify the decoded digest. + async fn inner_write_compressed( + &self, + instance: &InstanceInfo, + digest: DigestInfo, + digest_function: DigestHasherFunc, + wire_compressor: compressor::Value, + stream: WriteRequestStreamWrapper> + Unpin>, + ) -> Result, Error> { + // Register the upload in active_uploads so QueryWriteStatus can report + // compressed wire-byte progress while decoding. This mirrors what + // create_or_join_upload_stream does for uncompressed uploads. + let uuid_str = stream + .resource_info + .uuid + .as_deref() + .ok_or_else(|| make_input_err!("UUID must be set if writing compressed data"))?; + let uuid_key = parse_uuid_to_key(uuid_str); + let (bytes_received, _guard) = instance.track_compressed_upload(uuid_key); + + let (compressed_tx, compressed_rx) = make_buf_channel_pair(); + let (decompressed_tx, decompressed_rx) = make_buf_channel_pair(); + let store = instance.store.clone(); + let store_update_context = make_ctx_for_hash_func(digest_function)?; + let store_update_fut = async move { + store + .update( + digest, + decompressed_rx, + UploadSizeInfo::ExactSize(digest.size_bytes()), + ) + .await + .map(|_| ()) + .err_tip(|| "Failed to store decompressed data") + } + .with_context(store_update_context); + // Plain async future: decode progresses at the pace of the client + // upload and the store write without occupying a blocking-pool thread + // for the stream's lifetime. + let decode_fut = crate::wire_compression::stream_decode_compressed_upload( + compressed_rx, + wire_compressor, + digest, + digest_function, + decompressed_tx, + ); + let client_stream_fut = + process_compressed_client_stream(stream, compressed_tx, &bytes_received); + let (client_stream_result, decode_result, store_update_result) = + tokio::join!(client_stream_fut, decode_fut, store_update_fut); + + if let Err(err) = &client_stream_result + && err.code == Code::InvalidArgument + { + return Err(err.clone()); + } + if let Err(err) = &decode_result + && err.code == Code::InvalidArgument + { + return Err(err.clone()); + } + let mut upload_error = store_update_result.err(); + if let Err(err) = decode_result { + upload_error = Some(match upload_error { + Some(existing) => existing.merge(err), + None => err, + }); + } + if let Err(err) = client_stream_result { + upload_error = Some(match upload_error { + Some(existing) => existing.merge(err), + None => err, + }); + } + if let Some(err) = upload_error { + return Err(err); + } + + let committed_size = i64::try_from(bytes_received.load(Ordering::Acquire)) + .err_tip(|| "Compressed upload size was not convertible to i64")?; + Ok(Response::new(WriteResponse { committed_size })) + } + + /// Read a blob from the store, compress it with the given wire compressor, + /// and return it as a stream of chunked `ReadResponse`s. + async fn inner_read_compressed( + &self, + instance: &InstanceInfo, + digest: DigestInfo, + wire_compressor: compressor::Value, + read_request: ReadRequest, + ) -> Result { + struct ReaderState { + max_bytes_per_stream: usize, + rx: DropCloserReadHalf, + maybe_get_part_result: Option>, + maybe_encode_result: Option>, + get_part_fut: Pin> + Send>>, + encode_fut: Pin> + Send>>, + } + + impl ReaderState { + async fn finish(mut self, mut error: Option) -> Option { + let encode_result = if let Some(result) = self.maybe_encode_result.take() { + result + } else { + self.encode_fut.await + }; + if let Err(err) = encode_result { + error = Some(match error { + Some(existing) => err.merge(existing), + None => err, + }); + } + + let get_part_result = if let Some(result) = self.maybe_get_part_result.take() { + result + } else { + self.get_part_fut.await + }; + if let Err(err) = get_part_result { + error = Some(match error { + Some(existing) => err.merge(existing), + None => err, + }); + } + + error + } + } + + if read_request.read_limit != 0 { + return Err(make_input_err!( + "read_limit must be 0 when reading compressed blobs" + )); + } + if read_request.read_offset < 0 { + return Err(make_input_err!( + "read_offset must be non-negative when reading compressed blobs" + )); + } + let read_offset = u64::try_from(read_request.read_offset) + .err_tip(|| "Could not convert read_offset to u64")?; + + let (raw_tx, raw_rx) = make_buf_channel_pair(); + let (compressed_tx, compressed_rx) = make_buf_channel_pair(); + + let store = instance.store.clone(); + let get_part_fut = Box::pin(async move { + store + .get_part(digest, raw_tx, read_offset, None) + .await + .err_tip(|| "Failed to read blob for wire compression") + }); + // The encode runs as a plain async future: it must not occupy a + // blocking-pool thread for the stream's lifetime, because it only + // progresses at the client's drain rate. Dropping the returned + // stream drops this future, which tears the encode down exactly + // like the previous task-abort-on-drop did. + let encode_fut = Box::pin(crate::wire_compression::stream_encode_compressed_download( + raw_rx, + wire_compressor, + crate::wire_compression::ZSTD_COMPRESSION_LEVEL, + compressed_tx, + )); + + let state = Some(ReaderState { + max_bytes_per_stream: instance.max_bytes_per_stream, + rx: compressed_rx, + maybe_get_part_result: None, + maybe_encode_result: None, + get_part_fut, + encode_fut, + }); + + Ok(Box::pin(unfold(state, move |state| async { + enum ReadStep { + Response(ReadResponse), + Finish(Option), + } + + let mut state = state?; + let step = { + let mut response = ReadResponse::default(); + let consume_fut = state.rx.consume(Some(state.max_bytes_per_stream)); + tokio::pin!(consume_fut); + loop { + tokio::select! { + read_result = &mut consume_fut => { + match read_result { + Ok(bytes) => { + if bytes.is_empty() { + break ReadStep::Finish(None); + } + if bytes.len() > state.max_bytes_per_stream { + let err = make_err!(Code::Internal, "Returned compressed size was larger than read size"); + break ReadStep::Finish(Some(err)); + } + response.data = bytes; + trace!( + response.data = format!("", response.data.len()) + ); + break ReadStep::Response(response); + } + Err(e) => { + break ReadStep::Finish(Some(e)); + } + } + } + get_part_result = &mut state.get_part_fut, if state.maybe_get_part_result.is_none() => { + state.maybe_get_part_result = Some(get_part_result); + } + encode_result = &mut state.encode_fut, if state.maybe_encode_result.is_none() => { + state.maybe_encode_result = Some(encode_result); + } + } + } + }; + + match step { + ReadStep::Response(response) => Some((Ok(response), Some(state))), + ReadStep::Finish(error) => { + state.finish(error).await.map(|mut err| { + if err.code == Code::NotFound { + // Trim common NotFound details to match the identity read path. + err.messages.truncate(1); + } + error!(response = ?err); + (Err(err.into()), None) + }) + } + } + }))) + } + async fn inner_query_write_status( &self, query_request: &QueryWriteStatusRequest, @@ -953,7 +1351,10 @@ impl ByteStreamServer { let active_uploads = instance.active_uploads.lock(); if let Some((received_bytes, _maybe_idle_stream)) = active_uploads.get(&uuid_key) { return Ok(Response::new(QueryWriteStatusResponse { - committed_size: received_bytes.load(Ordering::Acquire) as i64, + committed_size: received_bytes + .load(Ordering::Acquire) + .try_into() + .unwrap_or(i64::MAX), // If we are in the active_uploads map, but the value is None, // it means the stream is not complete. complete: false, @@ -973,7 +1374,7 @@ impl ByteStreamServer { })); }; Ok(Response::new(QueryWriteStatusResponse { - committed_size: item_size as i64, + committed_size: item_size.try_into().unwrap_or(i64::MAX), complete: true, })) } @@ -996,7 +1397,8 @@ impl ByteStream for ByteStreamServer { let start_time = Instant::now(); let read_request = grpc_request.into_inner(); - let resource_info = ResourceInfo::new(&read_request.resource_name, false)?; + let resource_name = read_request.resource_name.clone(); + let resource_info = ResourceInfo::new(&resource_name, false)?; let instance_name = resource_info.instance_name.as_ref(); let expected_size = resource_info.expected_size as u64; let instance = self @@ -1004,6 +1406,11 @@ impl ByteStream for ByteStreamServer { .get(instance_name) .err_tip(|| format!("'instance_name' not configured for '{instance_name}'"))?; + trace!( + resource_name, + instance_name, expected_size, "Starting bytestream request" + ); + // Track read request instance .metrics @@ -1025,24 +1432,50 @@ impl ByteStream for ByteStreamServer { DigestHasherFunc::try_from, )?; - let resp = self - .inner_read(instance, digest, read_request) - .instrument(error_span!("bytestream_read")) - .with_context( - make_ctx_for_hash_func(digest_function).err_tip(|| "In BytestreamServer::read")?, - ) - .await - .err_tip(|| "In ByteStreamServer::read") - .map(|stream| -> Response { Response::new(Box::pin(stream)) }); + // Determine if the client requested wire-compressed data via compressed-blobs URI. + let wire_compressor = crate::wire_compression::resolve_wire_compressor( + resource_info.compressor.as_deref(), + instance.remote_cache_compression_enabled, + )?; + + let resp = if wire_compressor == compressor::Value::Identity { + // Uncompressed path — use the existing streaming read. + self.inner_read(instance, digest, read_request) + .instrument(error_span!("bytestream_read")) + .with_context( + make_ctx_for_hash_func(digest_function) + .err_tip(|| "In BytestreamServer::read")?, + ) + .await + .err_tip(|| "In ByteStreamServer::read") + .map(|stream| -> Response { Response::new(Box::pin(stream)) }) + } else { + // Compressed path — stream the requested raw range through zstd. + self.inner_read_compressed(instance, digest, wire_compressor, read_request) + .instrument(error_span!("bytestream_read_compressed")) + .with_context( + make_ctx_for_hash_func(digest_function) + .err_tip(|| "In BytestreamServer::read_compressed")?, + ) + .await + .err_tip(|| "In ByteStreamServer::read_compressed") + .map(|stream| -> Response { Response::new(Box::pin(stream)) }) + }; // Track metrics based on result + let elapsed = start_time.elapsed(); #[allow(clippy::cast_possible_truncation)] - let elapsed_ns = start_time.elapsed().as_nanos() as u64; + let elapsed_ns = elapsed.as_nanos() as u64; instance .metrics .read_duration_ns .fetch_add(elapsed_ns, Ordering::Relaxed); + trace!( + ?elapsed, + resource_name, instance_name, expected_size, "Completed bytestream request" + ); + match &resp { Ok(_) => { instance @@ -1111,14 +1544,71 @@ impl ByteStream for ByteStreamServer { return resp; } - let digest_function = stream - .resource_info - .digest_function - .as_deref() - .map_or_else( - || Ok(default_digest_hasher_func()), - DigestHasherFunc::try_from, - )?; + let default_digest_function = default_digest_hasher_func(); + let digest_function = match stream.resource_info.digest_function.as_deref() { + Some(value) => { + let digest_function = DigestHasherFunc::try_from(value)?; + if digest_function != default_digest_function + && self + .reported_digest_function_mismatches + .lock() + .insert((digest_function, default_digest_function)) + { + warn!( + client_digest_function = %digest_function, + server_default_digest_function = %default_digest_function, + "ByteStream client declared a digest function that differs from the server default; the client-declared function will be used for this upload, but clients using different digest functions generate different cache keys and will not share cache hits; configure global.default_digest_hash_function and all clients to use the same digest function" + ); + } + digest_function + } + None => default_digest_function, + }; + + // Determine if the client is sending wire-compressed data via compressed-blobs URI. + let wire_compressor = crate::wire_compression::resolve_wire_compressor( + stream.resource_info.compressor.as_deref(), + instance.remote_cache_compression_enabled, + )?; + + // For compressed uploads, stream compressed wire bytes through the + // decoder and store the resulting raw bytes. + if wire_compressor != compressor::Value::Identity { + let result = self + .inner_write_compressed(instance, digest, digest_function, wire_compressor, stream) + .instrument(error_span!("bytestream_write_compressed")) + .await + .err_tip(|| "In ByteStreamServer::write_compressed"); + + // Track metrics based on result + #[allow(clippy::cast_possible_truncation)] + let elapsed_ns = start_time.elapsed().as_nanos() as u64; + instance + .metrics + .write_duration_ns + .fetch_add(elapsed_ns, Ordering::Relaxed); + + match &result { + Ok(_) => { + instance + .metrics + .write_requests_success + .fetch_add(1, Ordering::Relaxed); + instance + .metrics + .bytes_written_total + .fetch_add(expected_size, Ordering::Relaxed); + } + Err(_) => { + instance + .metrics + .write_requests_failure + .fetch_add(1, Ordering::Relaxed); + } + } + + return result.map_err(Into::into); + } // Check if store supports direct oneshot updates (bypasses channel overhead). // Use fast-path only when: @@ -1150,21 +1640,13 @@ impl ByteStream for ByteStreamServer { }; let result = if use_oneshot { - self.inner_write_oneshot(instance, digest, stream) + self.inner_write_oneshot(instance, digest, digest_function, stream) .instrument(error_span!("bytestream_write_oneshot")) - .with_context( - make_ctx_for_hash_func(digest_function) - .err_tip(|| "In BytestreamServer::write")?, - ) .await .err_tip(|| "In ByteStreamServer::write (oneshot)") } else { - self.inner_write(instance, digest, stream) + self.inner_write(instance, digest, digest_function, stream) .instrument(error_span!("bytestream_write")) - .with_context( - make_ctx_for_hash_func(digest_function) - .err_tip(|| "In BytestreamServer::write")?, - ) .await .err_tip(|| "In ByteStreamServer::write") }; diff --git a/nativelink-service/src/capabilities_server.rs b/nativelink-service/src/capabilities_server.rs index 6e4102033..ea9d74999 100644 --- a/nativelink-service/src/capabilities_server.rs +++ b/nativelink-service/src/capabilities_server.rs @@ -15,7 +15,9 @@ use std::collections::HashMap; use std::sync::Arc; -use nativelink_config::cas_server::{CapabilitiesConfig, InstanceName, WithInstanceName}; +use nativelink_config::cas_server::{ + CapabilitiesConfig, CasStoreConfig, InstanceName, WithInstanceName, +}; use nativelink_error::{Error, ResultExt}; use nativelink_proto::build::bazel::remote::execution::v2::capabilities_server::{ Capabilities, CapabilitiesServer as Server, @@ -24,8 +26,8 @@ use nativelink_proto::build::bazel::remote::execution::v2::digest_function::Valu use nativelink_proto::build::bazel::remote::execution::v2::priority_capabilities::PriorityRange; use nativelink_proto::build::bazel::remote::execution::v2::symlink_absolute_path_strategy::Value as SymlinkAbsolutePathStrategy; use nativelink_proto::build::bazel::remote::execution::v2::{ - ActionCacheUpdateCapabilities, CacheCapabilities, ExecutionCapabilities, - GetCapabilitiesRequest, PriorityCapabilities, ServerCapabilities, + ActionCacheUpdateCapabilities, CacheCapabilities, ExecutionCapabilities, FastCdc2020Params, + GetCapabilitiesRequest, PriorityCapabilities, ServerCapabilities, compressor, }; use nativelink_proto::build::bazel::semver::SemVer; use nativelink_scheduler::known_platform_property_provider::KnownPlatformPropertyProvider; @@ -33,21 +35,52 @@ use nativelink_util::digest_hasher::default_digest_hasher_func; use tonic::{Request, Response, Status}; use tracing::{Level, instrument}; +use crate::wire_compression::RemoteCacheCompressionInstances; + const MAX_BATCH_TOTAL_SIZE: i64 = 64 * 1024; #[derive(Debug, Default)] pub struct CapabilitiesServer { supported_node_properties_for_instance: HashMap>, + // Kept separate from `supported_node_properties_for_instance`: that map is sent + // verbatim to clients as `ExecutionCapabilities.supported_node_properties` (REAPI + // file metadata like mtime/unix mode), while compression is advertised through + // `CacheCapabilities.supported_compressors`. Merging them would leak a fake node + // property onto the wire. + remote_cache_compression_instances: RemoteCacheCompressionInstances, + chunking_params_for_instance: HashMap, } impl CapabilitiesServer { pub async fn new( configs: &[WithInstanceName], scheduler_map: &HashMap>, + remote_cache_compression_instances: &RemoteCacheCompressionInstances, + cas_configs: &[WithInstanceName], ) -> Result { + let mut chunking_params_for_instance = HashMap::new(); + for cas_config in cas_configs { + if let Some(chunking_config) = &cas_config.experimental_chunking { + let avg_chunk_size_bytes = chunking_config + .validated_avg_chunk_size_bytes() + .err_tip(|| { + format!( + "In 'experimental_chunking' of instance '{}'", + cas_config.instance_name + ) + })?; + chunking_params_for_instance.insert( + cas_config.instance_name.clone(), + FastCdc2020Params { + avg_chunk_size_bytes, + seed: 0, + }, + ); + } + } + let mut supported_node_properties_for_instance = HashMap::new(); for config in configs { - let mut properties = Vec::new(); if let Some(remote_execution_cfg) = &config.remote_execution { let scheduler = scheduler_map @@ -58,7 +91,7 @@ impl CapabilitiesServer { remote_execution_cfg.scheduler ) })?; - for platform_key in scheduler + let properties = scheduler .get_known_properties(&config.instance_name) .await .err_tip(|| { @@ -66,15 +99,15 @@ impl CapabilitiesServer { "Failed to get platform properties for {}", config.instance_name ) - })? - { - properties.push(platform_key.clone()); - } + })?; + supported_node_properties_for_instance + .insert(config.instance_name.clone(), properties); } - supported_node_properties_for_instance.insert(config.instance_name.clone(), properties); } Ok(Self { supported_node_properties_for_instance, + remote_cache_compression_instances: remote_cache_compression_instances.clone(), + chunking_params_for_instance, }) } @@ -119,6 +152,16 @@ impl Capabilities for CapabilitiesServer { ], }); + let supported_compressors = if self + .remote_cache_compression_instances + .enabled_for(&instance_name) + { + vec![compressor::Value::Zstd.into()] + } else { + Vec::new() + }; + + let chunking_params = self.chunking_params_for_instance.get(&instance_name); let resp = ServerCapabilities { cache_capabilities: Some(CacheCapabilities { digest_functions: vec![ @@ -131,8 +174,13 @@ impl Capabilities for CapabilitiesServer { cache_priority_capabilities: None, max_batch_total_size_bytes: MAX_BATCH_TOTAL_SIZE, symlink_absolute_path_strategy: SymlinkAbsolutePathStrategy::Disallowed.into(), - supported_compressors: vec![], - supported_batch_update_compressors: vec![], + supported_compressors: supported_compressors.clone(), + supported_batch_update_compressors: supported_compressors, + max_cas_blob_size_bytes: 0, + split_blob_support: chunking_params.is_some(), + splice_blob_support: chunking_params.is_some(), + fast_cdc_2020_params: chunking_params.copied(), + rep_max_cdc_params: None, }), execution_capabilities, deprecated_api_version: None, diff --git a/nativelink-service/src/cas_server.rs b/nativelink-service/src/cas_server.rs index 68e146686..953c2bc6e 100644 --- a/nativelink-service/src/cas_server.rs +++ b/nativelink-service/src/cas_server.rs @@ -13,38 +13,169 @@ // limitations under the License. use core::convert::Into; -use core::pin::Pin; +use core::pin::{Pin, pin}; +use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use core::time::Duration; use std::collections::{HashMap, VecDeque}; use bytes::Bytes; +use fastcdc::v2020::{AsyncStreamCDC, Normalization}; use futures::stream::{FuturesUnordered, Stream}; use futures::{StreamExt, TryStreamExt}; -use nativelink_config::cas_server::{CasStoreConfig, WithInstanceName}; +use nativelink_config::cas_server::{CasStoreConfig, InstanceName, WithInstanceName}; use nativelink_error::{Code, Error, ResultExt, error_if, make_err, make_input_err}; +use nativelink_metric::{ + MetricFieldData, MetricKind, MetricPublishKnownKindData, MetricsComponent, group, publish, +}; use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_storage_server::{ ContentAddressableStorage, ContentAddressableStorageServer as Server, }; use nativelink_proto::build::bazel::remote::execution::v2::{ BatchReadBlobsRequest, BatchReadBlobsResponse, BatchUpdateBlobsRequest, - BatchUpdateBlobsResponse, Directory, FindMissingBlobsRequest, FindMissingBlobsResponse, - GetTreeRequest, GetTreeResponse, batch_read_blobs_response, batch_update_blobs_response, - compressor, + BatchUpdateBlobsResponse, Digest, Directory, FindMissingBlobsRequest, FindMissingBlobsResponse, + GetTreeRequest, GetTreeResponse, SpliceBlobRequest, SpliceBlobResponse, SplitBlobRequest, + SplitBlobResponse, batch_read_blobs_response, batch_update_blobs_response, chunking_function, + compressor, digest_function, }; use nativelink_proto::google::rpc::Status as GrpcStatus; use nativelink_store::ac_utils::get_and_decode_digest; use nativelink_store::grpc_store::GrpcStore; use nativelink_store::store_manager::StoreManager; +use nativelink_util::buf_channel::make_buf_channel_pair; use nativelink_util::common::DigestInfo; -use nativelink_util::digest_hasher::make_ctx_for_hash_func; -use nativelink_util::store_trait::{Store, StoreLike}; +use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc, make_ctx_for_hash_func}; +use nativelink_util::spawn_blocking; +use nativelink_util::store_trait::{Store, StoreLike, UploadSizeInfo}; use opentelemetry::context::FutureExt; +use prost::Message; +use tokio_util::io::StreamReader; use tonic::{Request, Response, Status}; -use tracing::{Instrument, Level, debug, error_span, instrument}; +use tracing::{Instrument, Level, debug, error_span, instrument, warn}; + +use crate::wire_compression::RemoteCacheCompressionInstances; + +/// Metrics for the experimental `SplitBlob`/`SpliceBlob` chunking RPCs. +/// The split hit rate (`split_hits` / `split_requests_total`) indicates how +/// often chunked downloads could be served; the spliced/split byte totals +/// bound the transfer volume flowing through the chunked paths. +#[derive(Debug, Default)] +pub struct ChunkingMetrics { + /// Total `SpliceBlob` requests received on chunking-enabled instances. + pub splice_requests_total: AtomicU64, + /// `SpliceBlob` requests that were no-ops because the blob and its chunk + /// layout were already registered. + pub splice_already_exists: AtomicU64, + /// `SpliceBlob` requests rejected because the re-assembled blob did not + /// match the expected digest or size. + pub splice_verification_failures: AtomicU64, + /// Total bytes of blobs successfully re-assembled by `SpliceBlob`. + pub splice_bytes_total: AtomicU64, + /// Total `SplitBlob` requests received on chunking-enabled instances. + pub split_requests_total: AtomicU64, + /// `SplitBlob` requests served from a stored chunk layout. + pub split_hits: AtomicU64, + /// `SplitBlob` requests that could not be served because the blob was + /// not present in the CAS. + pub split_misses: AtomicU64, + /// `SplitBlob` requests served by chunking the blob on demand because + /// no stored layout was available (or its chunks were evicted). + pub split_chunked_on_demand: AtomicU64, + /// Total bytes of blobs served as chunk layouts by `SplitBlob`. + pub split_bytes_total: AtomicU64, +} + +impl MetricsComponent for ChunkingMetrics { + fn publish( + &self, + _kind: MetricKind, + field_metadata: MetricFieldData, + ) -> Result { + let _enter = group!(field_metadata.name).entered(); + + publish!( + "splice_requests_total", + &self.splice_requests_total, + MetricKind::Counter, + "Total SpliceBlob requests received" + ); + publish!( + "splice_already_exists", + &self.splice_already_exists, + MetricKind::Counter, + "SpliceBlob requests that were no-ops because blob and layout already existed" + ); + publish!( + "splice_verification_failures", + &self.splice_verification_failures, + MetricKind::Counter, + "SpliceBlob requests rejected due to digest or size mismatch" + ); + publish!( + "splice_bytes_total", + &self.splice_bytes_total, + MetricKind::Counter, + "Total bytes of blobs re-assembled by SpliceBlob" + ); + publish!( + "split_requests_total", + &self.split_requests_total, + MetricKind::Counter, + "Total SplitBlob requests received" + ); + publish!( + "split_hits", + &self.split_hits, + MetricKind::Counter, + "SplitBlob requests served from a stored chunk layout" + ); + publish!( + "split_misses", + &self.split_misses, + MetricKind::Counter, + "SplitBlob requests where the blob was not present" + ); + publish!( + "split_chunked_on_demand", + &self.split_chunked_on_demand, + MetricKind::Counter, + "SplitBlob requests served by chunking the blob on demand" + ); + publish!( + "split_bytes_total", + &self.split_bytes_total, + MetricKind::Counter, + "Total bytes of blobs served as chunk layouts by SplitBlob" + ); + + Ok(MetricPublishKnownKindData::Component) + } +} + +/// Per-instance state for the experimental chunking RPCs. +#[derive(Debug, Clone)] +struct ChunkingInstance { + /// Store holding blob-digest -> chunk-layout mappings. + index_store: Store, + /// Average chunk size used for server-side `FastCDC` 2020 chunking. + avg_chunk_size_bytes: u32, + /// Maximum number of chunks accepted in a `SpliceBlob` request or + /// produced by on-demand chunking. + max_chunk_count: usize, +} + +impl ChunkingInstance { + /// Maximum serialized layout size consistent with `max_chunk_count`. + const fn max_layout_size(&self) -> u64 { + self.max_chunk_count as u64 * MAX_LAYOUT_BYTES_PER_CHUNK + } +} #[derive(Debug)] pub struct CasServer { - stores: HashMap, + stores: HashMap, + remote_cache_compression_instances: RemoteCacheCompressionInstances, + chunking_instances: HashMap, + chunking_metrics: ChunkingMetrics, } type GetTreeStream = Pin> + Send + 'static>>; @@ -52,25 +183,111 @@ type GetTreeStream = Pin> /// Per-blob deadline applied inside `BatchReadBlobs` / `BatchUpdateBlobs`. const BATCH_PER_BLOB_TIMEOUT: Duration = Duration::from_secs(30); +/// Maximum size of a single chunk accepted in a `SpliceBlob` request. +/// Deliberately looser than the largest chunk the server ever advertises +/// (4x the maximum allowed average = 4 MiB) so clients using their own +/// chunking function are still accepted. Together with `CHUNK_CONCURRENCY` +/// this bounds the memory a single splice request can pin. +const MAX_SPLICE_CHUNK_SIZE: u64 = 16 * 1024 * 1024; + +/// Generous upper bound for the serialized size of one chunk entry in a +/// stored layout (hash string of up to 128 hex characters plus varints and +/// field tags). Multiplied by the configured `max_chunk_count` this caps +/// layout reads from the index store; a larger entry is corrupt. A truncated +/// read is detected (and treated as no layout) by the size consistency check +/// in `read_chunk_layout`. +const MAX_LAYOUT_BYTES_PER_CHUNK: u64 = 160; + +/// Number of chunk reads/writes kept in flight while re-assembling or +/// chunking a blob. Matches the `DedupStore` concurrency default. +const CHUNK_CONCURRENCY: usize = 10; + impl CasServer { pub fn new( configs: &[WithInstanceName], store_manager: &StoreManager, + remote_cache_compression_instances: &RemoteCacheCompressionInstances, ) -> Result { let mut stores = HashMap::with_capacity(configs.len()); + let mut chunking_instances = HashMap::new(); for config in configs { let store = store_manager.get_store(&config.cas_store).ok_or_else(|| { make_input_err!("'cas_store': '{}' does not exist", config.cas_store) })?; + if let Some(chunking_config) = &config.experimental_chunking { + let avg_chunk_size_bytes = chunking_config + .validated_avg_chunk_size_bytes() + .err_tip(|| { + format!( + "In 'experimental_chunking' of instance '{}'", + config.instance_name + ) + })?; + if store.downcast_ref::(None).is_some() { + // SplitBlob/SpliceBlob for grpc-store-backed instances + // are forwarded to the backend, which owns the chunk + // layouts; a local index store is meaningless there. + error_if!( + chunking_config.index_store.is_some(), + "'experimental_chunking.index_store' of instance '{}' must not be set when 'cas_store' is a grpc store: SplitBlob/SpliceBlob are forwarded to the backend", + config.instance_name + ); + // No ChunkingInstance: the forwarding shortcut in the + // handlers takes over before local chunking is reached. + stores.insert(config.instance_name.clone(), store); + continue; + } + let index_store_name = chunking_config.index_store.as_ref().ok_or_else(|| { + make_input_err!( + "'experimental_chunking.index_store' of instance '{}' is required", + config.instance_name + ) + })?; + // Chunk layouts are stored under the digests of the blobs + // they describe but do not hash to them, so writing them + // into the CAS itself would overwrite blob content. + error_if!( + index_store_name == &config.cas_store, + "'experimental_chunking.index_store' of instance '{}' must not be the same store as 'cas_store'", + config.instance_name + ); + let index_store = store_manager.get_store(index_store_name).ok_or_else(|| { + make_input_err!( + "'experimental_chunking.index_store': '{index_store_name}' does not exist" + ) + })?; + let avg_chunk_size_bytes = u32::try_from(avg_chunk_size_bytes) + .err_tip(|| "avg_chunk_size_bytes did not fit in u32")?; + let max_chunk_count = usize::try_from(chunking_config.resolved_max_chunk_count()) + .err_tip(|| "max_chunk_count did not fit in usize")?; + chunking_instances.insert( + config.instance_name.clone(), + ChunkingInstance { + index_store, + avg_chunk_size_bytes, + max_chunk_count, + }, + ); + } stores.insert(config.instance_name.clone(), store); } - Ok(Self { stores }) + Ok(Self { + stores, + remote_cache_compression_instances: remote_cache_compression_instances.clone(), + chunking_instances, + chunking_metrics: ChunkingMetrics::default(), + }) } pub fn into_service(self) -> Server { Server::new(self) } + /// Metrics for the experimental `SplitBlob`/`SpliceBlob` RPCs. + pub const fn chunking_metrics(&self) -> &ChunkingMetrics { + &self.chunking_metrics + } + async fn inner_find_missing_blobs( &self, request: FindMissingBlobsRequest, @@ -121,44 +338,50 @@ impl CasServer { } let store_ref = &store; + let remote_cache_compression_enabled = self + .remote_cache_compression_instances + .enabled_for(instance_name); let update_futures: FuturesUnordered<_> = request .requests .into_iter() - .map(|request| async move { - let digest = request - .digest - .clone() - .err_tip(|| "Digest not found in request")?; - let request_data = request.data; - let digest_info = DigestInfo::try_from(digest.clone())?; - let size_bytes = usize::try_from(digest_info.size_bytes()) - .err_tip(|| "Digest size_bytes was not convertible to usize")?; - error_if!( - size_bytes != request_data.len(), - "Digest for upload had mismatching sizes, digest said {} data said {}", - size_bytes, - request_data.len() - ); - // Apply a per-blob deadline so one slow upload does not - // make the whole batch hit the client's overall deadline. - let result = match tokio::time::timeout( - BATCH_PER_BLOB_TIMEOUT, - store_ref.update_oneshot(digest_info, request_data), - ) - .await - { - Ok(r) => r.err_tip(|| "Error writing to store"), - Err(_elapsed) => Err(make_err!( - Code::DeadlineExceeded, - "BatchUpdateBlobs per-blob timeout ({} s) elapsed for digest {}", - BATCH_PER_BLOB_TIMEOUT.as_secs(), - digest_info, - )), - }; - Ok::<_, Error>(batch_update_blobs_response::Response { - digest: Some(digest), - status: Some(result.map_or_else(Into::into, |()| GrpcStatus::default())), - }) + .map(|request| { + async move { + let digest = request + .digest + .clone() + .err_tip(|| "Digest not found in request")?; + let digest_info = DigestInfo::try_from(digest.clone())?; + let size_bytes = usize::try_from(digest_info.size_bytes()) + .err_tip(|| "Digest size_bytes was not convertible to usize")?; + + let store_data = crate::wire_compression::decompress_batch_update( + request.data, + request.compressor, + size_bytes, + remote_cache_compression_enabled, + ) + .await?; + // Apply a per-blob deadline so one slow upload does not + // make the whole batch hit the client's overall deadline. + let result = match tokio::time::timeout( + BATCH_PER_BLOB_TIMEOUT, + store_ref.update_oneshot(digest_info, store_data), + ) + .await + { + Ok(r) => r.err_tip(|| "Error writing to store"), + Err(_elapsed) => Err(make_err!( + Code::DeadlineExceeded, + "BatchUpdateBlobs per-blob timeout ({} s) elapsed for digest {}", + BATCH_PER_BLOB_TIMEOUT.as_secs(), + digest_info, + )), + }; + Ok::<_, Error>(batch_update_blobs_response::Response { + digest: Some(digest), + status: Some(result.map_or_else(Into::into, |()| GrpcStatus::default())), + }) + } }) .collect(); let responses = update_futures @@ -188,46 +411,77 @@ impl CasServer { } let store_ref = &store; + let remote_cache_compression_enabled = self + .remote_cache_compression_instances + .enabled_for(instance_name); + let client_accepts_zstd = remote_cache_compression_enabled + && request.acceptable_compressors.iter().any(|compressor_i32| { + compressor::Value::try_from(*compressor_i32) + .is_ok_and(|compressor| compressor == compressor::Value::Zstd) + }); let read_futures: FuturesUnordered<_> = request .digests .into_iter() - .map(|digest| async move { - let digest_copy = DigestInfo::try_from(digest.clone())?; - // TODO(palfrey) There is a security risk here of someone taking all the memory on the instance. - // Apply a per-blob deadline so one slow read does not - // make the whole batch hit the client's overall deadline. - let result = match tokio::time::timeout( - BATCH_PER_BLOB_TIMEOUT, - store_ref.get_part_unchunked(digest_copy, 0, None), - ) - .await - { - Ok(r) => r.err_tip(|| "Error reading from store"), - Err(_elapsed) => Err(make_err!( - Code::DeadlineExceeded, - "BatchReadBlobs per-blob timeout ({} s) elapsed for digest {}", - BATCH_PER_BLOB_TIMEOUT.as_secs(), - digest_copy, - )), - }; - let (status, data) = result.map_or_else( - |mut e| { - if e.code == Code::NotFound { - // Trim the error code. Not Found is quite common and we don't want to send a large - // error (debug) message for something that is common. We resize to just the last - // message as it will be the most relevant. - e.messages.resize_with(1, String::new); + .map(|digest| { + async move { + let digest_copy = DigestInfo::try_from(digest.clone())?; + // TODO(palfrey) There is a security risk here of someone taking all the memory on the instance. + // Apply a per-blob deadline so one slow read does not + // make the whole batch hit the client's overall deadline. + let result = match tokio::time::timeout( + BATCH_PER_BLOB_TIMEOUT, + store_ref.get_part_unchunked(digest_copy, 0, None), + ) + .await + { + Ok(r) => r.err_tip(|| "Error reading from store"), + Err(_elapsed) => Err(make_err!( + Code::DeadlineExceeded, + "BatchReadBlobs per-blob timeout ({} s) elapsed for digest {}", + BATCH_PER_BLOB_TIMEOUT.as_secs(), + digest_copy, + )), + }; + let (status, data, response_compressor) = match result { + Ok(raw_data) => { + let (output_data, chosen_compressor) = if client_accepts_zstd { + let data_for_compression = raw_data.clone(); + match spawn_blocking!("cas_encode_compressed_download", move || { + crate::wire_compression::compress_for_batch_read( + data_for_compression, + ) + }) + .await + { + Ok(compressed_result) => compressed_result, + Err(e) => { + warn!("Wire compression task failed for digest {:?}, falling back to identity: {}", digest, e); + (raw_data, compressor::Value::Identity) + } + } + } else { + (raw_data, compressor::Value::Identity) + }; + + (GrpcStatus::default(), output_data, chosen_compressor) } - (e.into(), Bytes::new()) - }, - |v| (GrpcStatus::default(), v), - ); - Ok::<_, Error>(batch_read_blobs_response::Response { - status: Some(status), - digest: Some(digest), - compressor: compressor::Value::Identity.into(), - data, - }) + Err(mut e) => { + if e.code == Code::NotFound { + // Trim the error code. Not Found is quite common and we don't want to send a large + // error (debug) message for something that is common. We resize to just the last + // message as it will be the most relevant. + e.messages.resize_with(1, String::new); + } + (e.into(), Bytes::new(), compressor::Value::Identity) + } + }; + Ok::<_, Error>(batch_read_blobs_response::Response { + status: Some(status), + digest: Some(digest), + compressor: response_compressor.into(), + data, + }) + } }) .collect(); let responses = read_futures @@ -330,6 +584,533 @@ impl CasServer { }) .right_stream()) } + + /// Returns the CAS store for an instance and its chunking state, or + /// `Unimplemented` when chunking is not enabled for it. Grpc-store-backed + /// instances never reach this: their handlers forward the RPC to the + /// backend first. + fn chunking_instance(&self, instance_name: &str) -> Result<(Store, ChunkingInstance), Error> { + let store = self + .stores + .get(instance_name) + .err_tip(|| format!("'instance_name' not configured for '{instance_name}'"))? + .clone(); + let chunking_instance = self + .chunking_instances + .get(instance_name) + .ok_or_else(|| { + make_err!( + Code::Unimplemented, + "Blob chunking is not enabled for instance '{instance_name}'" + ) + })? + .clone(); + Ok((store, chunking_instance)) + } + + /// Returns the backend `GrpcStore` when the instance's CAS is a grpc + /// proxy store, in which case chunking RPCs are forwarded verbatim. + fn grpc_store_for_instance(&self, instance_name: &str) -> Option<&GrpcStore> { + self.stores + .get(instance_name) + .and_then(|store| store.downcast_ref::(None)) + } + + /// Returns the digest function explicitly requested by the client, or + /// `None` when the field was left unset. REAPI's length-based inference + /// cannot be used as a fallback here: SHA256 and BLAKE3 digests are both + /// 32 bytes, and `NativeLink` announces support for both. Notably Bazel + /// (9.1.1) leaves this field unset even when running with + /// `--digest_function=blake3`. + fn explicit_hasher_func(digest_function_value: i32) -> Option { + digest_function::Value::try_from(digest_function_value) + .ok() + .and_then(|value| DigestHasherFunc::try_from(value).ok()) + } + + /// Determines the digest function of a blob already present in the CAS + /// by hashing its content with each supported function and returning the + /// one that reproduces `blob_digest`. + async fn infer_blob_hasher_func( + store: &Store, + blob_digest: DigestInfo, + ) -> Result { + const CANDIDATES: [DigestHasherFunc; 2] = + [DigestHasherFunc::Sha256, DigestHasherFunc::Blake3]; + let (tx, rx) = make_buf_channel_pair(); + let read_store = store.clone(); + let read_fut = async move { + let mut tx = tx; + read_store + .get_part(blob_digest, &mut tx, 0, None) + .await + .err_tip(|| "Failed to read blob in infer_blob_hasher_func") + }; + let hash_fut = async move { + let mut rx = rx; + let mut hashers = CANDIDATES.map(|func| func.hasher()); + loop { + let data = rx + .recv() + .await + .err_tip(|| "In infer_blob_hasher_func::recv")?; + if data.is_empty() { + break; // EOF. + } + for hasher in &mut hashers { + hasher.update(&data); + } + } + Ok::<_, Error>(hashers.map(|mut hasher| hasher.finalize_digest())) + }; + let (read_res, hash_res) = futures::join!(read_fut, hash_fut); + let computed_digests = read_res.merge(hash_res)?; + CANDIDATES + .iter() + .zip(computed_digests) + .find(|(_, computed)| *computed == blob_digest) + .map(|(func, _)| *func) + .ok_or_else(|| { + make_err!( + Code::NotFound, + "Blob {blob_digest} does not match any supported digest function; no split information available" + ) + }) + } + + /// Returns the display names of the chunks missing from the CAS. The + /// existence check also touches present chunks, which extends their + /// lifetimes on a best-effort basis (stores that answer existence from a + /// cache may not promote the underlying entries). + async fn missing_chunks(store: &Store, chunk_digests: &[Digest]) -> Result, Error> { + let mut digest_infos = Vec::with_capacity(chunk_digests.len()); + for digest in chunk_digests { + digest_infos + .push(DigestInfo::try_from(digest.clone()).err_tip(|| "Invalid chunk digest")?); + } + let chunk_keys: Vec<_> = digest_infos.iter().map(|digest| (*digest).into()).collect(); + let sizes = store + .has_many(&chunk_keys) + .await + .err_tip(|| "In missing_chunks")?; + Ok(sizes + .iter() + .zip(&digest_infos) + .filter(|(maybe_size, _)| maybe_size.is_none()) + .map(|(_, digest)| digest.to_string()) + .collect()) + } + + /// Reads the chunk layout registered for a blob. Returns `None` when no + /// usable layout exists: not registered, undecodable, or inconsistent + /// with the blob size (which also rejects entries truncated by the read + /// cap below). + async fn read_chunk_layout( + chunking_instance: &ChunkingInstance, + blob_digest: DigestInfo, + ) -> Option { + let layout_bytes = chunking_instance + .index_store + .get_part_unchunked(blob_digest, 0, Some(chunking_instance.max_layout_size())) + .await + .ok()?; + let layout = SplitBlobResponse::decode(layout_bytes).ok()?; + // A usable layout must reproduce the blob exactly, so the chunk + // sizes have to add up to the blob size. + let mut total_size: u64 = 0; + for digest in &layout.chunk_digests { + total_size = total_size.checked_add(u64::try_from(digest.size_bytes).ok()?)?; + } + (total_size == blob_digest.size_bytes()).then_some(layout) + } + + /// Writes the chunk layout for a blob to the index store. This is the + /// write side of the format `read_chunk_layout` expects. + async fn write_chunk_layout( + index_store: &Store, + blob_digest: DigestInfo, + layout: &SplitBlobResponse, + ) -> Result<(), Error> { + index_store + .update_oneshot(blob_digest, layout.encode_to_vec().into()) + .await + .err_tip(|| "Failed to write chunk layout to index store") + } + + async fn inner_split_blob( + &self, + request: SplitBlobRequest, + ) -> Result, Error> { + // If we are a GrpcStore we forward the RPC to the backend, which + // owns chunking and the layout index for proxied instances. + if let Some(grpc_store) = self.grpc_store_for_instance(&request.instance_name) { + return grpc_store.split_blob(Request::new(request)).await; + } + let (store, chunking_instance) = self.chunking_instance(&request.instance_name)?; + self.chunking_metrics + .split_requests_total + .fetch_add(1, Ordering::Relaxed); + + let blob_digest: DigestInfo = request + .blob_digest + .err_tip(|| "Expected blob_digest to exist in SplitBlobRequest")? + .try_into() + .err_tip(|| "In SplitBlobRequest::blob_digest")?; + + // The existence check also touches the blob, extending its lifetime + // (best effort) as suggested by the REAPI spec for SplitBlob. + let (blob_exists, maybe_layout) = futures::join!( + store.has(blob_digest), + Self::read_chunk_layout(&chunking_instance, blob_digest), + ); + if blob_exists.err_tip(|| "In split_blob")?.is_none() { + self.chunking_metrics + .split_misses + .fetch_add(1, Ordering::Relaxed); + return Err(make_err!( + Code::NotFound, + "Blob {blob_digest} not present in the CAS in split_blob" + )); + } + + // Serve the registered layout if it is still fully backed by chunks + // in the CAS. Any problem with it (missing, corrupt, evicted chunks, + // or a transient chunk existence-check failure) falls back to + // re-chunking the blob below. + if let Some(layout) = maybe_layout + && matches!( + Self::missing_chunks(&store, &layout.chunk_digests).await, + Ok(missing) if missing.is_empty() + ) + { + self.chunking_metrics + .split_hits + .fetch_add(1, Ordering::Relaxed); + self.chunking_metrics + .split_bytes_total + .fetch_add(blob_digest.size_bytes(), Ordering::Relaxed); + return Ok(Response::new(layout)); + } + + // No usable layout: chunk the blob on demand with FastCDC 2020, + // store the chunks and the layout, and serve the result. This is the + // path taken for blobs that were uploaded whole (e.g. outputs + // produced by remote execution workers). + let split_response = self + .chunk_blob_on_demand( + &store, + &chunking_instance, + blob_digest, + request.digest_function, + ) + .await?; + self.chunking_metrics + .split_chunked_on_demand + .fetch_add(1, Ordering::Relaxed); + self.chunking_metrics + .split_bytes_total + .fetch_add(blob_digest.size_bytes(), Ordering::Relaxed); + Ok(Response::new(split_response)) + } + + /// Chunks the blob with `FastCDC` 2020 (normalization level 2, parameters + /// derived from the configured average chunk size per the REAPI spec), + /// uploads any missing chunks to the CAS, registers the layout in the + /// index store, and returns it. + async fn chunk_blob_on_demand( + &self, + store: &Store, + chunking_instance: &ChunkingInstance, + blob_digest: DigestInfo, + digest_function_value: i32, + ) -> Result { + let avg_size = chunking_instance.avg_chunk_size_bytes; + let (min_size, max_size) = (avg_size / 4, avg_size * 4); + // Chunk digests MUST use the blob's digest function. When the client + // leaves the field unset it has to be inferred from the blob content + // (an extra read pass) since the hash length alone is ambiguous. + let hasher_func = match Self::explicit_hasher_func(digest_function_value) { + Some(hasher_func) => hasher_func, + None => Self::infer_blob_hasher_func(store, blob_digest).await?, + }; + + let (tx, rx) = make_buf_channel_pair(); + let read_store = store.clone(); + // `tx` is moved into the future so that when the read finishes or + // fails it is dropped, which terminates the chunking stream. + let read_fut = async move { + let mut tx = tx; + read_store + .get_part(blob_digest, &mut tx, 0, None) + .await + .err_tip(|| format!("Failed to read blob {blob_digest} in chunk_blob_on_demand")) + }; + // `rx` is owned by this future so an early error return drops it, + // which aborts the in-flight read instead of leaving it blocked. + let chunk_fut = async move { + let mut bytes_reader = StreamReader::new(rx); + let mut cdc = AsyncStreamCDC::with_level( + &mut bytes_reader, + min_size, + avg_size, + max_size, + Normalization::Level2, + ); + // Chunks are hashed and stored CHUNK_CONCURRENCY at a time while + // the blob keeps streaming; `buffered` preserves chunk order. + let chunk_digests: Vec = pin!(cdc.as_stream()) + .map(|chunk_result| async { + let chunk = chunk_result + .map_err(|e| make_err!(Code::Internal, "Failed to chunk blob: {e:?}")) + .err_tip(|| "In chunk_blob_on_demand")?; + let mut hasher = hasher_func.hasher(); + hasher.update(&chunk.data); + let chunk_digest = hasher.finalize_digest(); + // The existence check also touches pre-existing chunks, + // extending their lifetimes (best effort). FastCDC is + // deterministic, so repeated splits of similar blobs + // mostly find their chunks present. + if store + .has(chunk_digest) + .await + .err_tip(|| "In chunk_blob_on_demand")? + .is_none() + { + store + .update_oneshot(chunk_digest, chunk.data.into()) + .await + .err_tip(|| { + format!( + "Failed to store chunk {chunk_digest} in chunk_blob_on_demand" + ) + })?; + } + Ok::(chunk_digest.into()) + }) + .buffered(CHUNK_CONCURRENCY) + .try_collect() + .await?; + Ok::, Error>(chunk_digests) + }; + let (read_res, chunk_res) = futures::join!(read_fut, chunk_fut); + // Prefer the read error (the chunker error is usually a consequence + // of it); merge keeps both messages when both fail. + let chunk_digests = read_res + .merge(chunk_res) + .err_tip(|| "Failed to chunk blob in chunk_blob_on_demand")?; + if chunk_digests.len() > chunking_instance.max_chunk_count { + return Err(make_err!( + Code::NotFound, + "Blob {blob_digest} produced {} chunks, exceeding the configured max_chunk_count of {}; no split information available", + chunk_digests.len(), + chunking_instance.max_chunk_count + )); + } + + let split_response = SplitBlobResponse { + chunk_digests, + chunking_function: chunking_function::Value::FastCdc2020.into(), + }; + Self::write_chunk_layout(&chunking_instance.index_store, blob_digest, &split_response) + .await?; + Ok(split_response) + } + + async fn inner_splice_blob( + &self, + request: SpliceBlobRequest, + ) -> Result, Error> { + // If we are a GrpcStore we forward the RPC to the backend, which + // owns chunking and the layout index for proxied instances. + if let Some(grpc_store) = self.grpc_store_for_instance(&request.instance_name) { + return grpc_store.splice_blob(Request::new(request)).await; + } + let (store, chunking_instance) = self.chunking_instance(&request.instance_name)?; + let index_store = chunking_instance.index_store; + self.chunking_metrics + .splice_requests_total + .fetch_add(1, Ordering::Relaxed); + + let blob_digest: DigestInfo = request + .blob_digest + .err_tip(|| "Expected blob_digest to exist in SpliceBlobRequest")? + .try_into() + .err_tip(|| "In SpliceBlobRequest::blob_digest")?; + + error_if!( + request.chunk_digests.is_empty(), + "chunk_digests must not be empty in splice_blob" + ); + error_if!( + request.chunk_digests.len() > chunking_instance.max_chunk_count, + "Request has {} chunk_digests, expected at most {} in splice_blob", + request.chunk_digests.len(), + chunking_instance.max_chunk_count + ); + let mut chunk_digests = Vec::with_capacity(request.chunk_digests.len()); + let mut total_size: u64 = 0; + for digest in &request.chunk_digests { + let digest_info = DigestInfo::try_from(digest.clone()) + .err_tip(|| "In SpliceBlobRequest::chunk_digests")?; + error_if!( + digest_info.size_bytes() == 0 || digest_info.size_bytes() > MAX_SPLICE_CHUNK_SIZE, + "Chunk {digest_info} has invalid size, expected to be in range (0, {MAX_SPLICE_CHUNK_SIZE}] in splice_blob" + ); + total_size += digest_info.size_bytes(); + chunk_digests.push(digest_info); + } + if total_size != blob_digest.size_bytes() { + self.chunking_metrics + .splice_verification_failures + .fetch_add(1, Ordering::Relaxed); + return Err(make_err!( + Code::InvalidArgument, + "Sum of chunk sizes ({total_size}) does not match the expected blob size ({}) in splice_blob", + blob_digest.size_bytes() + )); + } + + // One round of existence checks: the chunks (which also touches + // them, best-effort extending their lifetimes), the blob, and the + // registered layout. + let (missing_chunks, blob_exists, layout_exists) = futures::join!( + Self::missing_chunks(&store, &request.chunk_digests), + store.has(blob_digest), + index_store.has(blob_digest), + ); + let missing_chunks = missing_chunks.err_tip(|| "In splice_blob")?; + if !missing_chunks.is_empty() { + return Err(make_err!( + Code::NotFound, + "Chunk(s) [{}] not present in the CAS in splice_blob", + missing_chunks.join(", ") + )); + } + // Fast path: if the blob and its chunk layout are already registered + // this request is a no-op. + if blob_exists.err_tip(|| "In splice_blob")?.is_some() + && layout_exists.err_tip(|| "In splice_blob")?.is_some() + { + self.chunking_metrics + .splice_already_exists + .fetch_add(1, Ordering::Relaxed); + return Ok(Response::new(SpliceBlobResponse { + blob_digest: Some(blob_digest.into()), + })); + } + + // Re-assemble the blob into the store: chunk reads are pipelined + // CHUNK_CONCURRENCY at a time while hashing and channel writes stay + // in chunk order. The digest is verified before the final EOF is + // sent, so a digest mismatch aborts the upload before the store + // commits it. + // When the client sets the digest function, verify with exactly that + // function. When it is unset the hash length is ambiguous (SHA256 + // and BLAKE3 are both 32 bytes), so hash with both candidates and + // accept whichever reproduces the expected digest. + let candidate_hasher_funcs: Vec = + match Self::explicit_hasher_func(request.digest_function) { + Some(hasher_func) => vec![hasher_func], + None => vec![DigestHasherFunc::Sha256, DigestHasherFunc::Blake3], + }; + let verification_failed = AtomicBool::new(false); + let verification_failed_ref = &verification_failed; + let (tx, rx) = make_buf_channel_pair(); + let send_store = store.clone(); + // `tx` is moved into the future so that an early error return drops + // it without an EOF, which aborts the in-flight store update instead + // of leaving it waiting for more data. + let send_fut = async move { + let mut tx = tx; + let mut hashers: Vec<_> = candidate_hasher_funcs + .iter() + .map(DigestHasherFunc::hasher) + .collect(); + let mut fetch_stream = futures::stream::iter(chunk_digests.into_iter().map( + move |chunk_digest| { + let store = send_store.clone(); + async move { + let data = store + .get_part_unchunked(chunk_digest, 0, None) + .await + .err_tip(|| { + format!("Failed to read chunk {chunk_digest} in splice_blob") + })?; + if u64::try_from(data.len()).unwrap_or(0) != chunk_digest.size_bytes() { + return Err(make_err!( + Code::Internal, + "Chunk {chunk_digest} content has length {}, expected {}, in splice_blob", + data.len(), + chunk_digest.size_bytes() + )); + } + Ok::(data) + } + }, + )) + .buffered(CHUNK_CONCURRENCY); + while let Some(data) = fetch_stream.next().await { + let data = data?; + for hasher in &mut hashers { + hasher.update(&data); + } + tx.send(data) + .await + .err_tip(|| "Failed to send chunk data in splice_blob")?; + } + drop(fetch_stream); + let computed_digests: Vec = hashers + .iter_mut() + .map(DigestHasher::finalize_digest) + .collect(); + if !computed_digests.contains(&blob_digest) { + verification_failed_ref.store(true, Ordering::Relaxed); + return Err(make_err!( + Code::InvalidArgument, + "Digest of spliced blob ({}) does not match the expected digest ({blob_digest}) in splice_blob", + computed_digests + .iter() + .map(ToString::to_string) + .collect::>() + .join(" / ") + )); + } + tx.send_eof() + .err_tip(|| "Failed to send EOF in splice_blob")?; + Ok::<(), Error>(()) + }; + let update_fut = store.update( + blob_digest, + rx, + UploadSizeInfo::ExactSize(blob_digest.size_bytes()), + ); + let (send_res, update_res) = futures::join!(send_fut, update_fut); + if verification_failed.load(Ordering::Relaxed) { + self.chunking_metrics + .splice_verification_failures + .fetch_add(1, Ordering::Relaxed); + } + // Prefer the sender error: it carries the reason the upload was + // aborted (e.g. the digest mismatch), the store error is usually a + // consequence; merge keeps both messages when both fail. + send_res + .merge(update_res) + .err_tip(|| "Failed to write spliced blob to store in splice_blob")?; + + // Persist the chunk layout so SplitBlob can serve it later. + let split_response = SplitBlobResponse { + chunk_digests: request.chunk_digests, + chunking_function: request.chunking_function, + }; + Self::write_chunk_layout(&index_store, blob_digest, &split_response).await?; + + self.chunking_metrics + .splice_bytes_total + .fetch_add(blob_digest.size_bytes(), Ordering::Relaxed); + Ok(Response::new(SpliceBlobResponse { + blob_digest: Some(blob_digest.into()), + })) + } } #[tonic::async_trait] @@ -443,4 +1224,59 @@ impl ContentAddressableStorage for CasServer { } resp } + + #[instrument( + err, + ret(level = Level::DEBUG), + level = Level::ERROR, + skip_all, + fields( + request.instance_name = ?grpc_request.get_ref().instance_name, + request.blob_digest = ?grpc_request.get_ref().blob_digest, + request.digest_function = ?grpc_request.get_ref().digest_function, + ) + )] + async fn split_blob( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + let digest_function = request.digest_function; + self.inner_split_blob(request) + .instrument(error_span!("cas_server_split_blob")) + .with_context( + make_ctx_for_hash_func(digest_function).err_tip(|| "In CasServer::split_blob")?, + ) + .await + .err_tip(|| "Failed on split_blob() command") + .map_err(Into::into) + } + + #[instrument( + err, + ret(level = Level::DEBUG), + level = Level::ERROR, + skip_all, + fields( + // Skip request.chunk_digests which is sometimes enormous. + request.instance_name = ?grpc_request.get_ref().instance_name, + request.blob_digest = ?grpc_request.get_ref().blob_digest, + request.digest_function = ?grpc_request.get_ref().digest_function, + ) + )] + async fn splice_blob( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + let digest_function = request.digest_function; + self.inner_splice_blob(request) + .instrument(error_span!("cas_server_splice_blob")) + .with_context( + make_ctx_for_hash_func(digest_function).err_tip(|| "In CasServer::splice_blob")?, + ) + .await + .err_tip(|| "Failed on splice_blob() command") + .map_err(Into::into) + } } diff --git a/nativelink-service/src/lib.rs b/nativelink-service/src/lib.rs index ece8e1f74..f549b6ec1 100644 --- a/nativelink-service/src/lib.rs +++ b/nativelink-service/src/lib.rs @@ -22,4 +22,5 @@ pub mod fetch_server; pub mod health_server; pub mod push_server; pub mod remote_asset_proto; +pub mod wire_compression; pub mod worker_api_server; diff --git a/nativelink-service/src/remote_asset_proto.rs b/nativelink-service/src/remote_asset_proto.rs index 2d1969051..2e5921baf 100644 --- a/nativelink-service/src/remote_asset_proto.rs +++ b/nativelink-service/src/remote_asset_proto.rs @@ -6,7 +6,7 @@ use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc}; use prost::Message; use prost_types::Timestamp; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct RemoteAssetQuery { pub uri: String, pub qualifiers: Vec, @@ -28,7 +28,7 @@ impl RemoteAssetQuery { } } -#[derive(Clone, PartialEq, prost::Message)] +#[derive(Clone, PartialEq, Eq, prost::Message)] pub struct RemoteAssetArtifact { #[prost(string, tag = "1")] pub uri: String, diff --git a/nativelink-service/src/wire_compression.rs b/nativelink-service/src/wire_compression.rs new file mode 100644 index 000000000..12ccd79f3 --- /dev/null +++ b/nativelink-service/src/wire_compression.rs @@ -0,0 +1,148 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Wire compression utilities for REAPI compressed-blobs. +//! +//! This module handles compression/decompression of blob data on the gRPC wire +//! between client and server, per the REAPI compressed-blobs specification. +//! This is orthogonal to at-rest compression (`CompressionStore` with LZ4). + +use std::collections::HashSet; + +use bytes::Bytes; +use nativelink_config::cas_server::{CapabilitiesConfig, InstanceName, WithInstanceName}; +use nativelink_error::{Code, Error, make_err, make_input_err}; +use nativelink_proto::build::bazel::remote::execution::v2::compressor; +use nativelink_util::spawn_blocking; +// The codecs are shared with client-side GrpcStore transfers; re-export so +// existing service callers keep their import paths. +pub use nativelink_util::wire_compression::{ + ZSTD_COMPRESSION_LEVEL, compress, decompress, stream_decode_compressed_upload, + stream_encode_compressed_download, +}; +use tracing::warn; + +/// Which instances accept and advertise REAPI compressed-blobs (zstd). +/// +/// Derived from `CapabilitiesConfig.remote_cache_compression` so that +/// advertisement (capabilities) and acceptance (ByteStream/CAS) cannot drift. +#[derive(Debug, Clone, Default)] +pub struct RemoteCacheCompressionInstances(HashSet); + +impl RemoteCacheCompressionInstances { + #[must_use] + pub fn from_capabilities_configs(configs: &[WithInstanceName]) -> Self { + Self( + configs + .iter() + .filter(|config| config.remote_cache_compression) + .map(|config| config.instance_name.clone()) + .collect(), + ) + } + + #[must_use] + pub fn from_enabled_instance_names( + instance_names: impl IntoIterator, + ) -> Self { + Self(instance_names.into_iter().collect()) + } + + #[must_use] + pub fn enabled_for(&self, instance_name: &str) -> bool { + self.0.contains(instance_name) + } +} + +/// Resolve a wire compressor from a URI compressor string (as it appears in +/// the `compressed-blobs/{compressor}/...` resource name) and validate it +/// against whether the instance supports remote cache compression. +/// +/// Returns `compressor::Value::Identity` when `compressor_str` is `None` or +/// `"identity"`. This is the single source of truth for URI-to-compressor +/// parsing so that `ByteStream` and any other callers stay consistent. +pub fn resolve_wire_compressor( + compressor_str: Option<&str>, + remote_cache_compression_enabled: bool, +) -> Result { + match compressor_str { + None | Some("identity") => Ok(compressor::Value::Identity), + Some("zstd") => { + if remote_cache_compression_enabled { + Ok(compressor::Value::Zstd) + } else { + Err(make_input_err!( + "Remote cache compression is not supported by this instance" + )) + } + } + Some(other) => Err(make_input_err!("Unsupported wire compressor: '{}'", other)), + } +} + +#[must_use] +pub fn compress_for_batch_read(data: Bytes) -> (Bytes, compressor::Value) { + match compress(data.clone(), compressor::Value::Zstd) { + Ok(compressed) => { + if compressed.len() < data.len() { + (compressed, compressor::Value::Zstd) + } else { + (data, compressor::Value::Identity) + } + } + Err(err) => { + warn!("Wire compression failed, falling back to identity: {}", err); + (data, compressor::Value::Identity) + } + } +} + +fn validate_identity_batch_update(data: Bytes, expected_size: usize) -> Result { + if data.len() != expected_size { + return Err(make_err!( + Code::InvalidArgument, + "Identity data size {} does not match expected size {}", + data.len(), + expected_size + )); + } + Ok(data) +} + +pub async fn decompress_batch_update( + data: Bytes, + compressor_i32: i32, + expected_size: usize, + remote_cache_compression_enabled: bool, +) -> Result { + let request_compressor = compressor::Value::try_from(compressor_i32) + .map_err(|_| make_input_err!("Unknown compressor value: {}", compressor_i32))?; + + match request_compressor { + compressor::Value::Identity => validate_identity_batch_update(data, expected_size), + compressor::Value::Zstd => { + if !remote_cache_compression_enabled { + return Err(make_input_err!( + "Remote cache compression is not supported by this instance" + )); + } + spawn_blocking!("cas_decode_compressed_upload", move || { + decompress(&data, compressor::Value::Zstd, expected_size) + }) + .await + .map_err(|e| make_err!(Code::Internal, "Decompression task failed: {}", e))? + } + other => Err(make_input_err!("Unsupported wire compressor: {:?}", other)), + } +} diff --git a/nativelink-service/tests/ac_server_test.rs b/nativelink-service/tests/ac_server_test.rs index 39f7a1944..6d1434914 100644 --- a/nativelink-service/tests/ac_server_test.rs +++ b/nativelink-service/tests/ac_server_test.rs @@ -61,7 +61,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; store_manager.add_store( "main_ac", store_factory( @@ -70,7 +70,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; Ok(store_manager) } @@ -198,7 +198,9 @@ async fn one_item_update_test() -> Result<(), Box> { ..Default::default() }; - let size_bytes = get_encoded_proto_size(&action_result)? as i64; + let size_bytes = get_encoded_proto_size(&action_result)? + .try_into() + .unwrap_or(i64::MAX); let raw_response = update_action_result( &ac_server, diff --git a/nativelink-service/tests/bep_server_test.rs b/nativelink-service/tests/bep_server_test.rs index ac5b735f9..8124130b5 100644 --- a/nativelink-service/tests/bep_server_test.rs +++ b/nativelink-service/tests/bep_server_test.rs @@ -48,13 +48,14 @@ use nativelink_util::common::encode_stream_proto; use nativelink_util::default_health_status_indicator; use nativelink_util::health_utils::HealthStatusIndicator; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use pretty_assertions::assert_eq; use prost::Message; use prost_types::Timestamp; -use tonic::codec::{Codec, ProstCodec}; +use tonic::codec::Codec; use tonic::{Request, Streaming, async_trait}; +use tonic_prost::ProstCodec; const BEP_STORE_NAME: &str = "main_bep"; @@ -69,7 +70,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; Ok(store_manager) } @@ -153,10 +154,7 @@ impl StoreDriver for FlakyStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { todo!(); } } @@ -173,7 +171,7 @@ async fn publish_lifecycle_event_retries_transient_store_failure() attempts: AtomicUsize::new(0), }); let store_manager = Arc::new(StoreManager::new()); - store_manager.add_store(BEP_STORE_NAME, Store::new(flaky.clone())); + store_manager.add_store(BEP_STORE_NAME, Store::new(flaky.clone()))?; let bep_server = make_bep_server(&store_manager)?; let request = PublishLifecycleEventRequest { @@ -432,7 +430,7 @@ async fn publish_build_tool_event_stream_test() -> Result<(), Box Result, Error> { None, ) .await?, - ); + )?; + Ok(store_manager) +} + +async fn make_verify_store_manager() -> Result, Error> { + let store_manager = Arc::new(StoreManager::new()); + store_manager.add_store( + "main_cas", + store_factory( + &StoreSpec::Verify(Box::new(VerifySpec { + verify_size: true, + verify_hash: true, + backend: StoreSpec::Memory(MemorySpec::default()), + })), + &store_manager, + None, + ) + .await?, + )?; Ok(store_manager) } fn make_bytestream_server( store_manager: &StoreManager, config: Option>>, +) -> Result { + make_bytestream_server_with_remote_cache_compression(store_manager, config, false) +} + +fn make_bytestream_server_with_remote_cache_compression( + store_manager: &StoreManager, + config: Option>>, + remote_cache_compression_enabled: bool, ) -> Result { let config = config.unwrap_or_else(|| { vec![WithInstanceName { @@ -83,7 +113,14 @@ fn make_bytestream_server( }, }] }); - ByteStreamServer::new(&config, store_manager) + let remote_cache_compression_instances = if remote_cache_compression_enabled { + RemoteCacheCompressionInstances::from_enabled_instance_names([ + "foo_instance_name".to_string() + ]) + } else { + RemoteCacheCompressionInstances::default() + }; + ByteStreamServer::new(&config, store_manager, &remote_cache_compression_instances) } fn make_stream( @@ -118,6 +155,50 @@ fn make_resource_name(data_len: impl core::fmt::Display) -> String { ) } +fn make_compressed_resource_name( + uuid: &str, + hash: &str, + data_len: impl core::fmt::Display, +) -> String { + make_compressed_resource_name_with_compressor("zstd", uuid, hash, data_len) +} + +fn make_compressed_resource_name_with_compressor( + compressor: &str, + uuid: &str, + hash: &str, + data_len: impl core::fmt::Display, +) -> String { + format!("{INSTANCE_NAME}/uploads/{uuid}/compressed-blobs/{compressor}/sha256/{hash}/{data_len}") +} + +fn sha256_hex(data: &[u8]) -> String { + let mut hasher = Sha256::new(); + hasher.update(data); + hex::encode(hasher.finalize()) +} + +fn blake3_hex(data: &[u8]) -> String { + let mut hasher = DigestHasherFunc::Blake3.hasher(); + hasher.update(data); + hasher.finalize_digest().packed_hash().to_string() +} + +async fn read_all_bytes( + bs_server: &ByteStreamServer, + read_request: ReadRequest, +) -> Result, tonic::Status> { + let mut read_stream = bs_server + .read(Request::new(read_request)) + .await? + .into_inner(); + let mut data = Vec::new(); + while let Some(result_read_response) = read_stream.next().await { + data.extend_from_slice(&result_read_response?.data); + } + Ok(data) +} + async fn server_and_client_stub( bs_server: ByteStreamServer, http_listener: HttpListener, @@ -230,13 +311,13 @@ pub async fn chunked_stream_receives_all_data() -> Result<(), Box Result<(), Box Result<(), Box> { + const WRITE_DATA: &[u8] = b"sha256 cache entry without a digest segment"; + + let hash = sha256_hex(WRITE_DATA); + let store_manager = make_verify_store_manager().await?; + let bs_server = Arc::new(make_bytestream_server(&store_manager, None)?); + let write_resource_name = format!( + "{INSTANCE_NAME}/uploads/2dccbdca-8d6f-490c-8748-b3c723cf67a8/blobs/{hash}/{}", + WRITE_DATA.len() + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server.clone(), None); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: write_resource_name, + write_offset: 0, + finish_write: true, + data: WRITE_DATA.to_vec().into(), + })?)) + .await?; + drop(tx); + join_handle.await??; + + let cached_data = read_all_bytes( + &bs_server, + ReadRequest { + resource_name: format!("{INSTANCE_NAME}/blobs/{hash}/{}", WRITE_DATA.len()), + read_offset: 0, + read_limit: 0, + }, + ) + .await?; + assert_eq!(cached_data, WRITE_DATA); + Ok(()) +} + +#[nativelink_test] +pub async fn explicit_blake3_write_overrides_sha256_default_with_warning() +-> Result<(), Box> { + const WRITE_DATA: &[u8] = b"content hashed with blake3"; + + let hash = blake3_hex(WRITE_DATA); + let digest = DigestInfo::try_new(&hash, WRITE_DATA.len())?; + let store_manager = make_verify_store_manager().await?; + let bs_server = Arc::new(make_bytestream_server(&store_manager, None)?); + let store = store_manager.get_store("main_cas").unwrap(); + let resource_name = format!( + "{INSTANCE_NAME}/uploads/9eb44e87-1320-40e7-9154-bf19f3fdf94a/blobs/blake3/{hash}/{}", + WRITE_DATA.len() + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name, + write_offset: 0, + finish_write: true, + data: WRITE_DATA.to_vec().into(), + })?)) + .await?; + drop(tx); + + join_handle.await??; + assert_eq!(store.get_part_unchunked(digest, 0, None).await?, WRITE_DATA); + assert!(logs_contain( + "clients using different digest functions generate different cache keys and will not share cache hits" + )); + Ok(()) +} + +#[nativelink_test] +pub async fn resumed_blake3_write_keeps_declared_digest_function() +-> Result<(), Box> { + const WRITE_DATA: &[u8] = b"resumed content hashed with blake3"; + const BYTE_SPLIT_OFFSET: usize = 12; + + let hash = blake3_hex(WRITE_DATA); + let digest = DigestInfo::try_new(&hash, WRITE_DATA.len())?; + let store_manager = make_verify_store_manager().await?; + let bs_server = Arc::new(make_bytestream_server(&store_manager, None)?); + let store = store_manager.get_store("main_cas").unwrap(); + let resource_name = format!( + "{INSTANCE_NAME}/uploads/4dcec57e-1389-4ab5-b188-4a59f22ceb4b/blobs/blake3/{hash}/{}", + WRITE_DATA.len() + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server.clone(), None); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: resource_name.clone(), + write_offset: 0, + finish_write: false, + data: WRITE_DATA[..BYTE_SPLIT_OFFSET].to_vec().into(), + })?)) + .await?; + drop(tx); + assert!( + join_handle.await?.is_err(), + "the disconnected partial write should remain resumable" + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name, + write_offset: BYTE_SPLIT_OFFSET.try_into()?, + finish_write: true, + data: WRITE_DATA[BYTE_SPLIT_OFFSET..].to_vec().into(), + })?)) + .await?; + drop(tx); + + join_handle.await??; + assert_eq!(store.get_part_unchunked(digest, 0, None).await?, WRITE_DATA); + Ok(()) +} + #[nativelink_test] pub async fn resume_write_success() -> Result<(), Box> { const WRITE_DATA: &str = "12456789abcdefghijk"; @@ -324,7 +520,7 @@ pub async fn resume_write_success() -> Result<(), Box> { make_stream_and_writer_spawn(bs_server, Some(CompressionEncoding::Gzip)); { // Write the remainder of our data. - write_request.write_offset = BYTE_SPLIT_OFFSET as i64; + write_request.write_offset = BYTE_SPLIT_OFFSET.try_into().unwrap_or(i64::MAX); write_request.finish_write = true; write_request.data = WRITE_DATA[BYTE_SPLIT_OFFSET..].into(); tx.send(Frame::data(encode_stream_proto(&write_request)?)) @@ -405,7 +601,7 @@ pub async fn restart_write_success() -> Result<(), Box> } { // Write the remainder of our data. - write_request.write_offset = BYTE_SPLIT_OFFSET as i64; + write_request.write_offset = BYTE_SPLIT_OFFSET.try_into().unwrap_or(i64::MAX); write_request.finish_write = true; write_request.data = WRITE_DATA[BYTE_SPLIT_OFFSET..].into(); tx.send(Frame::data(encode_stream_proto(&write_request)?)) @@ -484,7 +680,7 @@ pub async fn restart_mid_stream_write_success() -> Result<(), Box Result<(), Box> { + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let raw_data = "zstd ByteStream committed_size regression ".repeat(256); + let compressed_data = zstd::bulk::compress(raw_data.as_bytes(), 3)?; + assert!( + compressed_data.len() < raw_data.len(), + "test data must compress to reproduce the committed_size mismatch" + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + let hash = sha256_hex(raw_data.as_bytes()); + let resource_name = make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb4b", + &hash, + raw_data.len(), + ); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name, + write_offset: 0, + finish_write: true, + data: compressed_data.clone().into(), + })?)) + .await?; + + let server_result = join_handle + .await + .expect("Failed to join") + .expect("Failed write"); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + assert_eq!( + store.get_part_unchunked(digest, 0, None).await?.as_ref(), + raw_data.as_bytes(), + "server should store the decompressed bytes" + ); + + let committed_size = server_result.into_inner().committed_size; + assert!( + committed_size == -1 + || committed_size == compressed_data.len().try_into().unwrap_or(i64::MAX), + "compressed write committed_size must be -1 or the compressed byte count {}; got {} for uncompressed size {}", + compressed_data.len(), + committed_size, + raw_data.len() + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_write_allows_wire_bytes_larger_than_digest_size() +-> Result<(), Box> { + let raw_data = b"x"; + let compressed_data = zstd::bulk::compress(raw_data, 3)?; + assert!( + compressed_data.len() > raw_data.len(), + "test data must expand when compressed to cover compressed wire sizes larger than the digest" + ); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + let hash = sha256_hex(raw_data); + let resource_name = make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb4c", + &hash, + raw_data.len(), + ); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name, + write_offset: 0, + finish_write: true, + data: compressed_data.clone().into(), + })?)) + .await?; + + let server_result = join_handle + .await + .expect("Failed to join") + .expect("Failed write"); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + assert_eq!( + store.get_part_unchunked(digest, 0, None).await?.as_ref(), + raw_data, + "server should store the decompressed bytes" + ); + + assert_eq!( + server_result.into_inner().committed_size, + compressed_data.len().try_into().unwrap_or(i64::MAX), + "compressed write should report the compressed wire byte count" + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_write_rejected_when_remote_cache_compression_disabled() +-> Result<(), Box> { + let raw_data = b"compression disabled"; + let compressed_data = zstd::bulk::compress(raw_data, 3)?; + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server(store_manager.as_ref(), None).expect("Failed to make server"), + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + let hash = sha256_hex(raw_data); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb54", + &hash, + raw_data.len(), + ), + write_offset: 0, + finish_write: true, + data: compressed_data.into(), + })?)) + .await?; + + let Err(status) = join_handle.await.expect("Failed to join") else { + panic!("zstd write should fail when remote cache compression is disabled"); + }; + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status + .message() + .contains("Remote cache compression is not supported"), + "unexpected error: {}", + status.message() + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_write_rejects_decompressed_digest_mismatch() +-> Result<(), Box> { + let raw_data = b"valid zstd payload with wrong digest"; + let compressed_data = zstd::bulk::compress(raw_data, 3)?; + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + let wrong_hash = sha256_hex(b"different data"); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb55", + &wrong_hash, + raw_data.len(), + ), + write_offset: 0, + finish_write: true, + data: compressed_data.into(), + })?)) + .await?; + + let Err(status) = join_handle.await.expect("Failed to join") else { + panic!("zstd write should fail when decompressed digest mismatches"); + }; + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status.message().contains("Decompressed digest"), + "unexpected error: {}", + status.message() + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn compressed_blobs_identity_write_and_read_use_identity_path() +-> Result<(), Box> { + let raw_data = Bytes::from_static(b"identity compressed-blobs payload"); + let hash = sha256_hex(raw_data.as_ref()); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server(store_manager.as_ref(), None).expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server.clone(), None); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: make_compressed_resource_name_with_compressor( + "identity", + "4dcec57e-1389-4ab5-b188-4a59f22ceb56", + &hash, + raw_data.len(), + ), + write_offset: 0, + finish_write: true, + data: raw_data.clone(), + })?)) + .await?; + + let server_result = join_handle + .await + .expect("Failed to join") + .expect("Failed write"); + assert_eq!( + server_result.into_inner().committed_size, + raw_data.len().try_into().unwrap_or(i64::MAX) + ); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + assert_eq!( + store.get_part_unchunked(digest, 0, None).await?, + raw_data, + "identity compressed-blobs write should store raw bytes" + ); + + let read_data = read_all_bytes( + bs_server.as_ref(), + ReadRequest { + resource_name: format!( + "{}/compressed-blobs/identity/{}/{}", + INSTANCE_NAME, + hash, + raw_data.len() + ), + read_offset: 0, + read_limit: raw_data.len().try_into().unwrap_or(i64::MAX), + }, + ) + .await?; + + assert_eq!(read_data.as_slice(), raw_data.as_ref()); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_write_streams_chunked_compressed_upload() +-> Result<(), Box> { + let raw_data = "streamed zstd upload ".repeat(4096); + let compressed_data = zstd::bulk::compress(raw_data.as_bytes(), 3)?; + assert!( + compressed_data.len() > 16, + "test data must produce multiple compressed chunks" + ); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + let hash = sha256_hex(raw_data.as_bytes()); + let resource_name = make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb4d", + &hash, + raw_data.len(), + ); + + let mut write_offset = 0usize; + while write_offset < compressed_data.len() { + let end = (write_offset + 7).min(compressed_data.len()); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: resource_name.clone(), + write_offset: write_offset.try_into().unwrap_or(i64::MAX), + finish_write: end == compressed_data.len(), + data: Bytes::copy_from_slice(&compressed_data[write_offset..end]), + })?)) + .await?; + write_offset = end; + } + + let server_result = join_handle + .await + .expect("Failed to join") + .expect("Failed write"); + assert_eq!( + server_result.into_inner().committed_size, + compressed_data.len().try_into().unwrap_or(i64::MAX) + ); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + assert_eq!( + store.get_part_unchunked(digest, 0, None).await?.as_ref(), + raw_data.as_bytes() + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_write_rejects_mismatched_compressed_write_offset_before_decompressing() +-> Result<(), Box> { + let raw_data = b"offset check"; + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server, None); + let hash = sha256_hex(raw_data); + let resource_name = make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb50", + &hash, + raw_data.len(), + ); + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name, + write_offset: 1, + finish_write: true, + data: Bytes::from_static(b"not zstd"), + })?)) + .await?; + + let status = join_handle + .await + .expect("Failed to join") + .expect_err("Expected compressed write to fail"); + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status.message().contains("out of order compressed data"), + "unexpected error: {}", + status.message() + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_write_query_status_reports_compressed_wire_bytes() +-> Result<(), Box> { + let raw_data = "compressed query progress ".repeat(128); + let compressed_data = zstd::bulk::compress(raw_data.as_bytes(), 3)?; + let first_chunk_len = compressed_data.len() / 2; + assert!(first_chunk_len > 0); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + + let (tx, join_handle) = make_stream_and_writer_spawn(bs_server.clone(), None); + let hash = sha256_hex(raw_data.as_bytes()); + let resource_name = make_compressed_resource_name( + "4dcec57e-1389-4ab5-b188-4a59f22ceb51", + &hash, + raw_data.len(), + ); + + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name: resource_name.clone(), + write_offset: 0, + finish_write: false, + data: Bytes::copy_from_slice(&compressed_data[..first_chunk_len]), + })?)) + .await?; + + let mut status_response = None; + for _ in 0..100 { + yield_now().await; + let response = bs_server + .query_write_status(Request::new(QueryWriteStatusRequest { + resource_name: resource_name.clone(), + })) + .await? + .into_inner(); + if response.committed_size == first_chunk_len.try_into().unwrap_or(i64::MAX) { + status_response = Some(response); + break; + } + } + assert_eq!( + status_response.err_tip(|| "compressed write progress was not reported")?, + QueryWriteStatusResponse { + committed_size: first_chunk_len.try_into().unwrap_or(i64::MAX), + complete: false, + } + ); + + tx.send(Frame::data(encode_stream_proto(&WriteRequest { + resource_name, + write_offset: first_chunk_len.try_into().unwrap_or(i64::MAX), + finish_write: true, + data: Bytes::copy_from_slice(&compressed_data[first_chunk_len..]), + })?)) + .await?; + + let server_result = join_handle + .await + .expect("Failed to join") + .expect("Failed write"); + assert_eq!( + server_result.into_inner().committed_size, + compressed_data.len().try_into().unwrap_or(i64::MAX) + ); + + Ok(()) +} + #[nativelink_test] pub async fn out_of_order_data_fails() -> Result<(), Box> { const WRITE_DATA: &str = "12456789abcdefghijk"; @@ -618,7 +1233,7 @@ pub async fn out_of_order_data_fails() -> Result<(), Box } { // Write data it already has. - write_request.write_offset = (BYTE_SPLIT_OFFSET - 1) as i64; + write_request.write_offset = (BYTE_SPLIT_OFFSET - 1).try_into().unwrap_or(i64::MAX); write_request.data = WRITE_DATA[(BYTE_SPLIT_OFFSET - 1)..].into(); tx.send(Frame::data(encode_stream_proto(&write_request)?)) .await?; @@ -629,7 +1244,7 @@ pub async fn out_of_order_data_fails() -> Result<(), Box ); { // Make sure stream was closed. - write_request.write_offset = (BYTE_SPLIT_OFFSET - 1) as i64; + write_request.write_offset = (BYTE_SPLIT_OFFSET - 1).try_into().unwrap_or(i64::MAX); write_request.data = WRITE_DATA[(BYTE_SPLIT_OFFSET - 1)..].into(); assert!( tx.send(Frame::data(encode_stream_proto(&write_request)?)) @@ -752,7 +1367,7 @@ pub async fn chunked_stream_reads_small_set_of_data() -> Result<(), Box Result<(), Box Result<(), Box> { + let raw_data = Bytes::from("zstd ByteStream compressed read ".repeat(256)); + let hash = sha256_hex(raw_data.as_ref()); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + store.update_oneshot(digest, raw_data.clone()).await?; + + let read_request = ReadRequest { + resource_name: format!( + "{}/compressed-blobs/zstd/{}/{}", + INSTANCE_NAME, + hash, + raw_data.len() + ), + read_offset: 0, + read_limit: 0, + }; + let mut read_stream = bs_server + .read(Request::new(read_request)) + .await? + .into_inner(); + + let mut compressed_data = Vec::new(); + while let Some(result_read_response) = read_stream.next().await { + compressed_data.extend_from_slice(&result_read_response?.data); + } + + assert!( + !compressed_data.is_empty(), + "Expected compressed read response to contain data" + ); + assert_ne!( + compressed_data.as_slice(), + raw_data.as_ref(), + "Expected compressible test data to differ from zstd wire bytes" + ); + + let decompressed_data = zstd::bulk::decompress(&compressed_data, raw_data.len())?; + assert_eq!( + decompressed_data.as_slice(), + raw_data.as_ref(), + "Expected decompressed read response to match stored raw blob" + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_read_rejected_when_remote_cache_compression_disabled() +-> Result<(), Box> { + let raw_data = Bytes::from_static(b"compression disabled read"); + let hash = sha256_hex(raw_data.as_ref()); + + let store_manager = make_store_manager().await?; + let bs_server = + make_bytestream_server(store_manager.as_ref(), None).expect("Failed to make server"); + + let Err(status) = bs_server + .read(Request::new(ReadRequest { + resource_name: format!( + "{}/compressed-blobs/zstd/{}/{}", + INSTANCE_NAME, + hash, + raw_data.len() + ), + read_offset: 0, + read_limit: 0, + })) + .await + else { + panic!("zstd read should fail when remote cache compression is disabled"); + }; + + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status + .message() + .contains("Remote cache compression is not supported"), + "unexpected error: {}", + status.message() + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_read_chunks_compressed_wire_bytes_by_configured_stream_size() +-> Result<(), Box> { + const MAX_BYTES_PER_STREAM: usize = 1; + + let raw_data = Bytes::from("zstd ByteStream compressed chunked read ".repeat(256)); + let hash = sha256_hex(raw_data.as_ref()); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression( + store_manager.as_ref(), + Some(vec![WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: ByteStreamConfig { + cas_store: "main_cas".to_string(), + max_bytes_per_stream: MAX_BYTES_PER_STREAM, + ..Default::default() + }, + }]), + true, + ) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + store.update_oneshot(digest, raw_data.clone()).await?; + + let read_request = ReadRequest { + resource_name: format!( + "{}/compressed-blobs/zstd/{}/{}", + INSTANCE_NAME, + hash, + raw_data.len() + ), + read_offset: 0, + read_limit: 0, + }; + let mut read_stream = bs_server + .read(Request::new(read_request)) + .await? + .into_inner(); + + let mut compressed_data = Vec::new(); + let mut chunk_lengths = Vec::new(); + while let Some(result_read_response) = read_stream.next().await { + let data = result_read_response?.data; + chunk_lengths.push(data.len()); + compressed_data.extend_from_slice(&data); + } + + assert!( + chunk_lengths.len() > 1, + "Expected compressed read response to be split into multiple chunks" + ); + assert!( + chunk_lengths + .iter() + .all(|chunk_len| *chunk_len <= MAX_BYTES_PER_STREAM), + "Expected compressed read chunks {chunk_lengths:?} to respect max_bytes_per_stream {MAX_BYTES_PER_STREAM}" + ); + + let decompressed_data = zstd::bulk::decompress(&compressed_data, raw_data.len())?; + assert_eq!( + decompressed_data.as_slice(), + raw_data.as_ref(), + "Expected decompressed chunked read response to match stored raw blob" + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_read_offset_applies_to_uncompressed_blob() +-> Result<(), Box> { + let raw_data = Bytes::from( + (0usize..4096) + .map(|i| u8::try_from((i * 31 + i / 7) % 251).expect("modulo 251 fits in u8")) + .collect::>(), + ); + let hash = sha256_hex(raw_data.as_ref()); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + store.update_oneshot(digest, raw_data.clone()).await?; + + let read_offset = 13usize; + + let ranged_data = read_all_bytes( + bs_server.as_ref(), + ReadRequest { + resource_name: format!( + "{}/compressed-blobs/zstd/{}/{}", + INSTANCE_NAME, + hash, + raw_data.len() + ), + read_offset: read_offset.try_into().unwrap_or(i64::MAX), + read_limit: 0, + }, + ) + .await?; + + let decompressed_data = zstd::bulk::decompress(&ranged_data, raw_data.len() - read_offset)?; + assert_eq!( + decompressed_data.as_slice(), + &raw_data.as_ref()[read_offset..], + "Expected read_offset to apply to the uncompressed blob before compression" + ); + + Ok(()) +} + +#[nativelink_test] +pub async fn zstd_read_rejects_nonzero_read_limit() -> Result<(), Box> { + let raw_data = Bytes::from( + (0usize..8192) + .map(|i| u8::try_from((i * 17 + i / 3) % 251).expect("modulo 251 fits in u8")) + .collect::>(), + ); + let hash = sha256_hex(raw_data.as_ref()); + + let store_manager = make_store_manager().await?; + let bs_server = Arc::new( + make_bytestream_server_with_remote_cache_compression(store_manager.as_ref(), None, true) + .expect("Failed to make server"), + ); + let store = store_manager.get_store("main_cas").unwrap(); + + let digest = DigestInfo::try_new(&hash, raw_data.len())?; + store.update_oneshot(digest, raw_data.clone()).await?; + + let Err(status) = bs_server + .read(Request::new(ReadRequest { + resource_name: format!( + "{}/compressed-blobs/zstd/{}/{}", + INSTANCE_NAME, + hash, + raw_data.len() + ), + read_offset: 0, + read_limit: 1, + })) + .await + else { + panic!("compressed read with read_limit should fail"); + }; + + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status.message().contains("read_limit must be 0"), + "unexpected error: {}", + status.message() + ); + Ok(()) } @@ -797,7 +1686,7 @@ pub async fn chunked_stream_reads_10mb_of_data() -> Result<(), Box Result<(), Error> { let result_fut = read_stream.next(); let result = result_fut.await.err_tip(|| "Expected result to be ready")?; - let expected_err_str = "status: NotFound, message: \"Key Digest(DigestInfo(\\\"0123456789abcdef000000000000000000000000000000000123456789abcdef-55\\\")) not found\", details: [], metadata: MetadataMap { headers: {} }"; + let expected_err_str = "code: 'Some requested entity was not found', message: \"Key Digest(DigestInfo(\\\"0123456789abcdef000000000000000000000000000000000123456789abcdef-55\\\")) not found\""; assert_eq!( Error::from(result.unwrap_err()), make_err!(Code::NotFound, "{expected_err_str}"), @@ -925,14 +1814,14 @@ pub async fn test_query_write_status_smoke_test() -> Result<(), Box Result<(), Box WithInstanceName { + WithInstanceName { + instance_name: instance_name.to_string(), + config: CapabilitiesConfig { + remote_execution: remote_execution.then(|| CapabilitiesRemoteExecutionConfig { + scheduler: SCHEDULER_NAME.to_string(), + }), + remote_cache_compression, + }, + } +} + +async fn get_capabilities( + server: &CapabilitiesServer, + instance_name: &str, +) -> Result { + server + .get_capabilities(Request::new(GetCapabilitiesRequest { + instance_name: instance_name.to_string(), + })) + .await + .map(tonic::Response::into_inner) +} + +#[nativelink_test] +async fn compression_only_instance_advertises_zstd_cache_capabilities() +-> Result<(), Box> { + let configs = [capabilities_config(COMPRESSION_INSTANCE, true, false)]; + let remote_cache_compression_instances = + RemoteCacheCompressionInstances::from_capabilities_configs(&configs); + let server = CapabilitiesServer::new( + &configs, + &HashMap::new(), + &remote_cache_compression_instances, + &[], + ) + .await?; + + let response = get_capabilities(&server, COMPRESSION_INSTANCE).await?; + let cache_capabilities = response + .cache_capabilities + .expect("cache capabilities should be set"); + + assert_eq!( + cache_capabilities.digest_functions, + vec![ + digest_function::Value::Sha256 as i32, + digest_function::Value::Blake3 as i32, + ], + "cache clients must be told that both digest functions are supported" + ); + assert_eq!( + cache_capabilities.supported_compressors, + vec![compressor::Value::Zstd as i32] + ); + assert_eq!( + cache_capabilities.supported_batch_update_compressors, + vec![compressor::Value::Zstd as i32] + ); + Ok(()) +} + +#[nativelink_test] +async fn compression_only_instance_does_not_advertise_execution_capabilities() +-> Result<(), Box> { + let configs = [capabilities_config(COMPRESSION_INSTANCE, true, false)]; + let remote_cache_compression_instances = + RemoteCacheCompressionInstances::from_capabilities_configs(&configs); + let server = CapabilitiesServer::new( + &configs, + &HashMap::new(), + &remote_cache_compression_instances, + &[], + ) + .await?; + + let response = get_capabilities(&server, COMPRESSION_INSTANCE).await?; + + assert!( + response.execution_capabilities.is_none(), + "compression-only instance should not advertise execution capabilities" + ); + Ok(()) +} + +#[nativelink_test] +async fn remote_execution_instance_advertises_execution_capabilities_and_node_properties() +-> Result<(), Box> { + let configs = [capabilities_config(EXECUTION_INSTANCE, false, true)]; + let remote_cache_compression_instances = + RemoteCacheCompressionInstances::from_capabilities_configs(&configs); + + let mock_scheduler = Arc::new(MockActionScheduler::new()); + let mut scheduler_map: HashMap> = HashMap::new(); + scheduler_map.insert(SCHEDULER_NAME.to_string(), mock_scheduler.clone()); + + let expected_properties = vec!["cpu".to_string(), "os".to_string()]; + let new_server_fut = CapabilitiesServer::new( + &configs, + &scheduler_map, + &remote_cache_compression_instances, + &[], + ); + let expected_scheduler_call_fut = + mock_scheduler.expect_get_known_properties(Ok(expected_properties.clone())); + let (server, scheduler_instance_name) = join!(new_server_fut, expected_scheduler_call_fut); + assert_eq!(scheduler_instance_name, EXECUTION_INSTANCE); + let server = server?; + + let response = get_capabilities(&server, EXECUTION_INSTANCE).await?; + let execution_capabilities = response + .execution_capabilities + .expect("execution capabilities should be set"); + + assert!(execution_capabilities.exec_enabled); + assert_eq!( + execution_capabilities.digest_function, + digest_function::Value::Sha256 as i32, + "the legacy execution digest field should report the server default" + ); + assert_eq!( + execution_capabilities.digest_functions, + vec![ + digest_function::Value::Sha256 as i32, + digest_function::Value::Blake3 as i32, + ], + "execution clients must be told that both digest functions are supported" + ); + assert_eq!( + execution_capabilities.supported_node_properties, + expected_properties + ); + Ok(()) +} diff --git a/nativelink-service/tests/cas_server_test.rs b/nativelink-service/tests/cas_server_test.rs index dccc90208..055bfe9a8 100644 --- a/nativelink-service/tests/cas_server_test.rs +++ b/nativelink-service/tests/cas_server_test.rs @@ -13,10 +13,12 @@ // limitations under the License. use core::pin::Pin; +use core::sync::atomic::Ordering; use core::time::Duration; use std::sync::Arc; use async_trait::async_trait; +use bytes::Bytes; use futures::StreamExt; use nativelink_config::cas_server::WithInstanceName; use nativelink_config::stores::{MemorySpec, StoreSpec}; @@ -27,22 +29,25 @@ use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_s use nativelink_proto::build::bazel::remote::execution::v2::{ BatchReadBlobsRequest, BatchReadBlobsResponse, BatchUpdateBlobsRequest, BatchUpdateBlobsResponse, Digest, Directory, DirectoryNode, FindMissingBlobsRequest, - GetTreeRequest, GetTreeResponse, NodeProperties, batch_read_blobs_response, - batch_update_blobs_request, batch_update_blobs_response, compressor, digest_function, + GetTreeRequest, GetTreeResponse, NodeProperties, SpliceBlobRequest, SplitBlobRequest, + SplitBlobResponse, batch_read_blobs_response, batch_update_blobs_request, + batch_update_blobs_response, chunking_function, compressor, digest_function, }; use nativelink_proto::google::rpc::Status as GrpcStatus; use nativelink_service::cas_server::CasServer; +use nativelink_service::wire_compression::RemoteCacheCompressionInstances; use nativelink_store::ac_utils::serialize_and_upload_message; use nativelink_store::default_store_factory::store_factory; use nativelink_store::store_manager::StoreManager; use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::common::DigestInfo; -use nativelink_util::digest_hasher::DigestHasherFunc; +use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc}; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use pretty_assertions::assert_eq; +use prost::Message; use prost_types::Timestamp; use tonic::{Code, Request}; @@ -62,7 +67,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; Ok(store_manager) } @@ -72,9 +77,27 @@ fn make_cas_server(store_manager: &StoreManager) -> Result { instance_name: "foo_instance_name".to_string(), config: nativelink_config::cas_server::CasStoreConfig { cas_store: "main_cas".to_string(), + experimental_chunking: None, + }, + }], + store_manager, + &RemoteCacheCompressionInstances::default(), + ) +} + +fn make_cas_server_with_zstd(store_manager: &StoreManager) -> Result { + CasServer::new( + &[WithInstanceName { + instance_name: "foo_instance_name".to_string(), + config: nativelink_config::cas_server::CasStoreConfig { + cas_store: "main_cas".to_string(), + experimental_chunking: None, }, }], store_manager, + &RemoteCacheCompressionInstances::from_enabled_instance_names([ + "foo_instance_name".to_string() + ]), ) } @@ -115,7 +138,7 @@ async fn store_one_item_existence() -> Result<(), Box> { instance_name: INSTANCE_NAME.to_string(), blob_digests: vec![Digest { hash: HASH1.to_string(), - size_bytes: VALUE.len() as i64, + size_bytes: VALUE.len().try_into().unwrap_or(i64::MAX), }], digest_function: digest_function::Value::Sha256.into(), })) @@ -143,15 +166,15 @@ async fn has_three_requests_one_bad_hash() -> Result<(), Box Result<(), Box> { let digest = Digest { hash: HASH1.to_string(), - size_bytes: VALUE2.len() as i64, + size_bytes: VALUE2.len().try_into().unwrap_or(i64::MAX), }; store @@ -233,11 +256,11 @@ async fn batch_read_blobs_read_two_blobs_success_one_fail() let digest1 = Digest { hash: HASH1.to_string(), - size_bytes: VALUE1.len() as i64, + size_bytes: VALUE1.len().try_into().unwrap_or(i64::MAX), }; let digest2 = Digest { hash: HASH2.to_string(), - size_bytes: VALUE2.len() as i64, + size_bytes: VALUE2.len().try_into().unwrap_or(i64::MAX), }; { // Insert dummy data. @@ -591,11 +614,11 @@ async fn batch_update_blobs_two_items_existence_with_third_missing() let digest1 = Digest { hash: HASH1.to_string(), - size_bytes: VALUE1.len() as i64, + size_bytes: VALUE1.len().try_into().unwrap_or(i64::MAX), }; let digest2 = Digest { hash: HASH2.to_string(), - size_bytes: VALUE2.len() as i64, + size_bytes: VALUE2.len().try_into().unwrap_or(i64::MAX), }; { @@ -656,12 +679,12 @@ async fn batch_update_blobs_two_items_existence_with_third_missing() blob_digests: vec![ Digest { hash: HASH1.to_string(), - size_bytes: VALUE1.len() as i64, + size_bytes: VALUE1.len().try_into().unwrap_or(i64::MAX), }, missing_digest.clone(), Digest { hash: HASH2.to_string(), - size_bytes: VALUE2.len() as i64, + size_bytes: VALUE2.len().try_into().unwrap_or(i64::MAX), }, ], digest_function: digest_function::Value::Sha256.into(), @@ -729,10 +752,7 @@ impl StoreDriver for StallStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { Ok(()) } } @@ -741,15 +761,17 @@ default_health_status_indicator!(StallStore); fn make_cas_server_with_stall_store(delay: Duration) -> Result { let store_manager = Arc::new(StoreManager::new()); - store_manager.add_store("main_cas", Store::new(Arc::new(StallStore { delay }))); + store_manager.add_store("main_cas", Store::new(Arc::new(StallStore { delay })))?; CasServer::new( &[WithInstanceName { instance_name: INSTANCE_NAME.to_string(), config: nativelink_config::cas_server::CasStoreConfig { cas_store: "main_cas".to_string(), + experimental_chunking: None, }, }], &store_manager, + &RemoteCacheCompressionInstances::default(), ) } @@ -760,11 +782,11 @@ async fn batch_update_blobs_per_blob_timeout_returns_deadline_exceeded() // Stall longer than `BATCH_PER_BLOB_TIMEOUT` (30 s) so the // per-blob timeout fires before the store ever resolves. - let cas_server = make_cas_server_with_stall_store(Duration::from_secs(120))?; + let cas_server = make_cas_server_with_stall_store(Duration::from_mins(2))?; let digest = Digest { hash: HASH1.to_string(), - size_bytes: VALUE.len() as i64, + size_bytes: VALUE.len().try_into().unwrap_or(i64::MAX), }; let raw_response = cas_server .batch_update_blobs(Request::new(BatchUpdateBlobsRequest { @@ -799,7 +821,7 @@ async fn batch_update_blobs_per_blob_timeout_returns_deadline_exceeded() #[nativelink_test(start_paused = true)] async fn batch_read_blobs_per_blob_timeout_returns_deadline_exceeded() -> Result<(), Box> { - let cas_server = make_cas_server_with_stall_store(Duration::from_secs(120))?; + let cas_server = make_cas_server_with_stall_store(Duration::from_mins(2))?; let digest = Digest { hash: HASH1.to_string(), @@ -835,3 +857,892 @@ async fn batch_read_blobs_per_blob_timeout_returns_deadline_exceeded() ); Ok(()) } + +#[nativelink_test] +async fn batch_update_blobs_zstd_compressed() -> Result<(), Box> { + let store_manager = make_store_manager().await?; + let cas_server = make_cas_server_with_zstd(&store_manager)?; + + // Use repetitive data so zstd compresses well. + let raw_data: Vec = "hello world ".repeat(100).into_bytes(); + + // Compute the sha256 digest. + let mut hasher = DigestHasherFunc::Sha256.hasher(); + DigestHasher::update(&mut hasher, &raw_data); + let digest_info = hasher.finalize_digest(); + let digest = Digest::from(&digest_info); + let compressed_data = zstd::bulk::compress(&raw_data, 3)?; + + let raw_response = cas_server + .batch_update_blobs(Request::new(BatchUpdateBlobsRequest { + instance_name: INSTANCE_NAME.to_string(), + requests: vec![batch_update_blobs_request::Request { + digest: Some(digest.clone()), + data: compressed_data.into(), + compressor: compressor::Value::Zstd.into(), + }], + digest_function: digest_function::Value::Sha256.into(), + })) + .await; + + let response = raw_response.unwrap().into_inner(); + assert_eq!(response.responses.len(), 1); + let entry = &response.responses[0]; + assert_eq!(entry.status.as_ref().map(|s| s.code), Some(Code::Ok as i32)); + + // Verify we can read the data back uncompressed (store holds raw data). + let raw_response = cas_server + .batch_read_blobs(Request::new(BatchReadBlobsRequest { + instance_name: INSTANCE_NAME.to_string(), + digests: vec![digest.clone()], + acceptable_compressors: vec![compressor::Value::Identity.into()], + digest_function: digest_function::Value::Sha256.into(), + })) + .await; + + let response = raw_response.unwrap().into_inner(); + assert_eq!(response.responses.len(), 1); + let entry = &response.responses[0]; + assert_eq!(entry.data.as_ref(), &raw_data); + assert_eq!(entry.compressor, compressor::Value::Identity as i32); + Ok(()) +} + +#[nativelink_test] +async fn batch_update_blobs_zstd_rejected_when_remote_cache_compression_disabled() +-> Result<(), Box> { + let store_manager = make_store_manager().await?; + let cas_server = make_cas_server(&store_manager)?; + + let raw_data = b"zstd disabled batch update"; + let compressed_data = zstd::bulk::compress(raw_data, 3)?; + let digest = Digest { + hash: HASH1.to_string(), + size_bytes: raw_data.len().try_into().unwrap_or(i64::MAX), + }; + + let Err(status) = cas_server + .batch_update_blobs(Request::new(BatchUpdateBlobsRequest { + instance_name: INSTANCE_NAME.to_string(), + requests: vec![batch_update_blobs_request::Request { + digest: Some(digest), + data: compressed_data.into(), + compressor: compressor::Value::Zstd.into(), + }], + digest_function: digest_function::Value::Sha256.into(), + })) + .await + else { + panic!("zstd BatchUpdateBlobs should fail when compression is disabled"); + }; + + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status + .message() + .contains("Remote cache compression is not supported"), + "unexpected error: {}", + status.message() + ); + + Ok(()) +} + +#[nativelink_test] +async fn batch_read_blobs_zstd_compressed() -> Result<(), Box> { + let store_manager = make_store_manager().await?; + let cas_server = make_cas_server_with_zstd(&store_manager)?; + + // Upload uncompressed data first. + let raw_data: Vec = "hello world ".repeat(100).into_bytes(); + let raw_size = raw_data.len().try_into().unwrap_or(i64::MAX); + + // Compute the sha256 digest. + let mut hasher = DigestHasherFunc::Sha256.hasher(); + DigestHasher::update(&mut hasher, &raw_data); + let digest_info = hasher.finalize_digest(); + let digest = Digest::from(&digest_info); + + cas_server + .batch_update_blobs(Request::new(BatchUpdateBlobsRequest { + instance_name: INSTANCE_NAME.to_string(), + requests: vec![batch_update_blobs_request::Request { + digest: Some(digest.clone()), + data: raw_data.clone().into(), + compressor: compressor::Value::Identity.into(), + }], + digest_function: digest_function::Value::Sha256.into(), + })) + .await?; + + // Request compressed data. + let raw_response = cas_server + .batch_read_blobs(Request::new(BatchReadBlobsRequest { + instance_name: INSTANCE_NAME.to_string(), + digests: vec![digest.clone()], + acceptable_compressors: vec![compressor::Value::Zstd.into()], + digest_function: digest_function::Value::Sha256.into(), + })) + .await; + + let response = raw_response.unwrap().into_inner(); + assert_eq!(response.responses.len(), 1); + let entry = &response.responses[0]; + assert_eq!(entry.compressor, compressor::Value::Zstd as i32); + + // Decompress and verify the data matches. + let decompressed = zstd::bulk::decompress(&entry.data, usize::try_from(raw_size)?)?; + assert_eq!(decompressed.as_slice(), raw_data.as_slice()); + Ok(()) +} + +#[nativelink_test] +async fn batch_read_blobs_zstd_falls_back_to_identity_when_not_smaller() +-> Result<(), Box> { + let store_manager = make_store_manager().await?; + let cas_server = make_cas_server_with_zstd(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + let raw_data = Bytes::from_static(b"x"); + let digest_info = DigestInfo::try_new(HASH1, raw_data.len())?; + store.update_oneshot(digest_info, raw_data.clone()).await?; + + let digest = Digest { + hash: HASH1.to_string(), + size_bytes: raw_data.len().try_into().unwrap_or(i64::MAX), + }; + let response = cas_server + .batch_read_blobs(Request::new(BatchReadBlobsRequest { + instance_name: INSTANCE_NAME.to_string(), + digests: vec![digest.clone()], + acceptable_compressors: vec![9999, compressor::Value::Zstd.into()], + digest_function: digest_function::Value::Sha256.into(), + })) + .await? + .into_inner(); + + assert_eq!(response.responses.len(), 1); + let entry = &response.responses[0]; + assert_eq!(entry.digest.as_ref(), Some(&digest)); + assert_eq!(entry.status, Some(GrpcStatus::default())); + assert_eq!(entry.compressor, compressor::Value::Identity as i32); + assert_eq!(entry.data, raw_data); + + Ok(()) +} + +const CHUNK1_VALUE: &str = "hello "; +const CHUNK2_VALUE: &str = "world"; + +async fn make_chunking_store_manager() -> Result, Error> { + let store_manager = make_store_manager().await?; + store_manager.add_store( + "chunk_index", + store_factory( + &StoreSpec::Memory(MemorySpec::default()), + &store_manager, + None, + ) + .await?, + )?; + Ok(store_manager) +} + +fn make_chunking_cas_server(store_manager: &StoreManager) -> Result { + make_chunking_cas_server_with_avg(store_manager, 0) +} + +fn make_chunking_cas_server_with_avg( + store_manager: &StoreManager, + avg_chunk_size_bytes: u64, +) -> Result { + CasServer::new( + &[WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: nativelink_config::cas_server::CasStoreConfig { + cas_store: "main_cas".to_string(), + experimental_chunking: Some(nativelink_config::cas_server::CasChunkingConfig { + index_store: Some("chunk_index".to_string()), + avg_chunk_size_bytes, + max_chunk_count: 0, + }), + }, + }], + store_manager, + &RemoteCacheCompressionInstances::default(), + ) +} + +/// Uploads the two test chunks to the store and returns their digests and +/// the digest of their concatenation. +async fn upload_test_chunks(store: &Store) -> Result<(Digest, Digest, Digest), Error> { + let chunk1_digest = Digest { + hash: HASH1.to_string(), + size_bytes: CHUNK1_VALUE.len().try_into().unwrap_or(i64::MAX), + }; + let chunk2_digest = Digest { + hash: HASH2.to_string(), + size_bytes: CHUNK2_VALUE.len().try_into().unwrap_or(i64::MAX), + }; + store + .update_oneshot( + DigestInfo::try_from(chunk1_digest.clone())?, + CHUNK1_VALUE.into(), + ) + .await?; + store + .update_oneshot( + DigestInfo::try_from(chunk2_digest.clone())?, + CHUNK2_VALUE.into(), + ) + .await?; + let mut hasher = DigestHasherFunc::Sha256.hasher(); + hasher.update(CHUNK1_VALUE.as_bytes()); + hasher.update(CHUNK2_VALUE.as_bytes()); + let blob_digest: Digest = hasher.finalize_digest().into(); + Ok((chunk1_digest, chunk2_digest, blob_digest)) +} + +#[nativelink_test] +async fn splice_and_split_round_trip() -> Result<(), Box> { + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + let (chunk1_digest, chunk2_digest, blob_digest) = upload_test_chunks(&store).await?; + + let splice_response = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest.clone()), + chunk_digests: vec![chunk1_digest.clone(), chunk2_digest.clone()], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(splice_response.blob_digest.as_ref(), Some(&blob_digest)); + + // The spliced blob must be materialized in the CAS so non-chunking + // clients can read it. + let blob_data = store + .get_part_unchunked(DigestInfo::try_from(blob_digest.clone())?, 0, None) + .await?; + assert_eq!(blob_data, format!("{CHUNK1_VALUE}{CHUNK2_VALUE}")); + + let split_response = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!( + split_response.chunk_digests, + vec![chunk1_digest, chunk2_digest] + ); + assert_eq!( + split_response.chunking_function, + i32::from(chunking_function::Value::FastCdc2020) + ); + + let metrics = cas_server.chunking_metrics(); + assert_eq!(metrics.splice_requests_total.load(Ordering::Relaxed), 1); + assert_eq!( + metrics.splice_bytes_total.load(Ordering::Relaxed), + (CHUNK1_VALUE.len() + CHUNK2_VALUE.len()) as u64 + ); + assert_eq!(metrics.split_requests_total.load(Ordering::Relaxed), 1); + assert_eq!(metrics.split_hits.load(Ordering::Relaxed), 1); + assert_eq!(metrics.split_misses.load(Ordering::Relaxed), 0); + Ok(()) +} + +#[nativelink_test] +async fn splice_blob_rejects_digest_mismatch() -> Result<(), Box> { + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + let (chunk1_digest, chunk2_digest, _blob_digest) = upload_test_chunks(&store).await?; + let total_size = chunk1_digest.size_bytes + chunk2_digest.size_bytes; + let wrong_blob_digest = Digest { + hash: HASH3.to_string(), + size_bytes: total_size, + }; + + let status = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(wrong_blob_digest.clone()), + chunk_digests: vec![chunk1_digest, chunk2_digest], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status + .message() + .contains("does not match the expected digest"), + "unexpected message: {}", + status.message() + ); + + // The blob must not have been committed to the CAS. + let blob_exists = store.has(DigestInfo::try_from(wrong_blob_digest)?).await?; + assert_eq!(blob_exists, None); + assert_eq!( + cas_server + .chunking_metrics() + .splice_verification_failures + .load(Ordering::Relaxed), + 1 + ); + Ok(()) +} + +#[nativelink_test] +async fn splice_blob_rejects_size_mismatch() -> Result<(), Box> { + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + let (chunk1_digest, chunk2_digest, blob_digest) = upload_test_chunks(&store).await?; + let wrong_blob_digest = Digest { + size_bytes: blob_digest.size_bytes + 1, + ..blob_digest + }; + + let status = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(wrong_blob_digest), + chunk_digests: vec![chunk1_digest, chunk2_digest], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status + .message() + .contains("does not match the expected blob size"), + "unexpected message: {}", + status.message() + ); + Ok(()) +} + +#[nativelink_test] +async fn splice_blob_missing_chunk_returns_not_found() -> Result<(), Box> { + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + // Only upload the first chunk. + let chunk1_digest = Digest { + hash: HASH1.to_string(), + size_bytes: CHUNK1_VALUE.len().try_into().unwrap_or(i64::MAX), + }; + store + .update_oneshot( + DigestInfo::try_from(chunk1_digest.clone())?, + CHUNK1_VALUE.into(), + ) + .await?; + let missing_chunk_digest = Digest { + hash: HASH2.to_string(), + size_bytes: CHUNK2_VALUE.len().try_into().unwrap_or(i64::MAX), + }; + let mut hasher = DigestHasherFunc::Sha256.hasher(); + hasher.update(CHUNK1_VALUE.as_bytes()); + hasher.update(CHUNK2_VALUE.as_bytes()); + let blob_digest: Digest = hasher.finalize_digest().into(); + + let status = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest), + chunk_digests: vec![chunk1_digest, missing_chunk_digest], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::NotFound); + Ok(()) +} + +#[nativelink_test] +async fn split_blob_absent_blob_returns_not_found() -> Result<(), Box> { + const VALUE: &str = "1"; + + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + + // The blob was never uploaded. + let status = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(Digest { + hash: HASH1.to_string(), + size_bytes: VALUE.len().try_into().unwrap_or(i64::MAX), + }), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::NotFound); + let metrics = cas_server.chunking_metrics(); + assert_eq!(metrics.split_requests_total.load(Ordering::Relaxed), 1); + assert_eq!(metrics.split_hits.load(Ordering::Relaxed), 0); + assert_eq!(metrics.split_misses.load(Ordering::Relaxed), 1); + Ok(()) +} + +#[nativelink_test] +async fn split_and_splice_disabled_return_unimplemented() -> Result<(), Box> +{ + const VALUE: &str = "1"; + + let store_manager = make_store_manager().await?; + let cas_server = make_cas_server(&store_manager)?; + + let digest = Digest { + hash: HASH1.to_string(), + size_bytes: VALUE.len().try_into().unwrap_or(i64::MAX), + }; + let split_status = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(digest.clone()), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(split_status.code(), Code::Unimplemented); + + let splice_status = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(digest.clone()), + chunk_digests: vec![digest], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(splice_status.code(), Code::Unimplemented); + Ok(()) +} + +#[nativelink_test] +async fn split_blob_chunks_small_blob_on_demand() -> Result<(), Box> { + const VALUE: &str = "1"; + + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + // Upload the blob whole (as a remote execution worker would) under its + // real digest, without ever calling SpliceBlob. + let mut hasher = DigestHasherFunc::Sha256.hasher(); + hasher.update(VALUE.as_bytes()); + let blob_digest: Digest = hasher.finalize_digest().into(); + store + .update_oneshot(DigestInfo::try_from(blob_digest.clone())?, VALUE.into()) + .await?; + + let split_response = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest.clone()), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + // A blob smaller than the minimum chunk size is a single chunk whose + // digest equals the blob digest. + assert_eq!(split_response.chunk_digests, vec![blob_digest]); + assert_eq!( + split_response.chunking_function, + i32::from(chunking_function::Value::FastCdc2020) + ); + let metrics = cas_server.chunking_metrics(); + assert_eq!(metrics.split_chunked_on_demand.load(Ordering::Relaxed), 1); + assert_eq!(metrics.split_hits.load(Ordering::Relaxed), 0); + Ok(()) +} + +#[nativelink_test] +async fn split_blob_chunks_large_blob_on_demand_and_reuses_layout() +-> Result<(), Box> { + // Use the smallest allowed average (1 KiB -> min 256, max 4096) so a + // small test blob still produces multiple chunks. + const AVG_CHUNK_SIZE: u64 = 1024; + const BLOB_SIZE: usize = 16 * 1024; + + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server_with_avg(&store_manager, AVG_CHUNK_SIZE)?; + let store = store_manager.get_store("main_cas").unwrap(); + + // Deterministic pseudo-random content so FastCDC finds content-defined + // boundaries. + let mut state = 0x9e37_79b9_u32; + let data: Vec = (0..BLOB_SIZE) + .map(|_| { + state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223); + (state >> 24) as u8 + }) + .collect(); + let blob_digest = Digest { + hash: HASH1.to_string(), + size_bytes: BLOB_SIZE.try_into().unwrap_or(i64::MAX), + }; + store + .update_oneshot( + DigestInfo::try_from(blob_digest.clone())?, + Bytes::from(data.clone()), + ) + .await?; + + let split_response = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest.clone()), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert!( + split_response.chunk_digests.len() > 1, + "expected multiple chunks, got {}", + split_response.chunk_digests.len() + ); + + // All chunks must be stored in the CAS and concatenate to the original + // blob in order. + let mut reassembled = Vec::with_capacity(BLOB_SIZE); + for chunk_digest in &split_response.chunk_digests { + let chunk_data = store + .get_part_unchunked(DigestInfo::try_from(chunk_digest.clone())?, 0, None) + .await?; + reassembled.extend_from_slice(&chunk_data); + } + assert_eq!(reassembled, data); + + // A second split must be served from the stored layout. + let second_response = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(second_response.chunk_digests, split_response.chunk_digests); + let metrics = cas_server.chunking_metrics(); + assert_eq!(metrics.split_requests_total.load(Ordering::Relaxed), 2); + assert_eq!(metrics.split_chunked_on_demand.load(Ordering::Relaxed), 1); + assert_eq!(metrics.split_hits.load(Ordering::Relaxed), 1); + Ok(()) +} + +#[nativelink_test] +async fn split_blob_falls_back_when_layout_unusable() -> Result<(), Box> { + const VALUE: &str = "1"; + + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + let index_store = store_manager.get_store("chunk_index").unwrap(); + + let mut hasher = DigestHasherFunc::Sha256.hasher(); + hasher.update(VALUE.as_bytes()); + let blob_digest: Digest = hasher.finalize_digest().into(); + store + .update_oneshot(DigestInfo::try_from(blob_digest.clone())?, VALUE.into()) + .await?; + + // Register a layout whose only chunk is not present in the CAS, + // simulating a chunk that was evicted after the layout was stored. + let stale_layout = SplitBlobResponse { + chunk_digests: vec![Digest { + hash: HASH2.to_string(), + size_bytes: VALUE.len().try_into().unwrap_or(i64::MAX), + }], + chunking_function: chunking_function::Value::FastCdc2020.into(), + }; + index_store + .update_oneshot( + DigestInfo::try_from(blob_digest.clone())?, + stale_layout.encode_to_vec().into(), + ) + .await?; + + // The unusable layout must be ignored and the blob re-chunked on demand. + let split_response = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest.clone()), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(split_response.chunk_digests, vec![blob_digest]); + let metrics = cas_server.chunking_metrics(); + assert_eq!(metrics.split_hits.load(Ordering::Relaxed), 0); + assert_eq!(metrics.split_chunked_on_demand.load(Ordering::Relaxed), 1); + Ok(()) +} + +#[nativelink_test] +async fn chunking_rejects_index_store_same_as_cas_store() -> Result<(), Box> +{ + let store_manager = make_store_manager().await?; + let error = CasServer::new( + &[WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: nativelink_config::cas_server::CasStoreConfig { + cas_store: "main_cas".to_string(), + experimental_chunking: Some(nativelink_config::cas_server::CasChunkingConfig { + index_store: Some("main_cas".to_string()), + avg_chunk_size_bytes: 0, + max_chunk_count: 0, + }), + }, + }], + &store_manager, + &RemoteCacheCompressionInstances::default(), + ) + .expect_err("expected same-store index_store to be rejected"); + assert!( + error + .to_string() + .contains("must not be the same store as 'cas_store'"), + "unexpected error: {error}" + ); + Ok(()) +} + +#[nativelink_test] +async fn chunking_on_grpc_store_forbids_index_store() -> Result<(), Box> { + let store_manager = Arc::new(StoreManager::new()); + store_manager.add_store( + "grpc_cas", + store_factory( + &StoreSpec::Grpc(nativelink_config::stores::GrpcSpec { + instance_name: "backend".to_string(), + endpoints: vec![nativelink_config::stores::GrpcEndpoint { + address: "http://localhost:1".to_string(), + tls_config: None, + concurrency_limit: None, + connect_timeout_s: 0, + tcp_keepalive_s: 0, + http2_keepalive_interval_s: 0, + http2_keepalive_timeout_s: 0, + }], + store_type: nativelink_config::stores::StoreType::Cas, + retry: nativelink_config::stores::Retry::default(), + max_concurrent_requests: 0, + connections_per_endpoint: 0, + rpc_timeout_s: 1, + use_legacy_resource_names: false, + headers: std::collections::HashMap::new(), + forward_headers: vec![], + experimental_read_batching: None, + experimental_remote_cache_compression: Some(false), + }), + &store_manager, + None, + ) + .await?, + )?; + + let make_config = |index_store: Option| { + vec![WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: nativelink_config::cas_server::CasStoreConfig { + cas_store: "grpc_cas".to_string(), + experimental_chunking: Some(nativelink_config::cas_server::CasChunkingConfig { + index_store, + avg_chunk_size_bytes: 0, + max_chunk_count: 0, + }), + }, + }] + }; + + // A local index store is meaningless when the RPCs are forwarded. + let error = CasServer::new( + &make_config(Some("grpc_cas".to_string())), + &store_manager, + &RemoteCacheCompressionInstances::default(), + ) + .expect_err("expected index_store on grpc store to be rejected"); + assert!( + error.to_string().contains("must not be set"), + "unexpected error: {error}" + ); + + // Without an `index_store` the configuration is valid: SplitBlob and + // SpliceBlob are forwarded to the backend. + CasServer::new( + &make_config(None), + &store_manager, + &RemoteCacheCompressionInstances::default(), + )?; + Ok(()) +} + +#[nativelink_test] +async fn max_chunk_count_limits_split_and_splice() -> Result<(), Box> { + // avg 1024 (min allowed) with `max_chunk_count` 2: the 16 KiB test blob + // chunks to more than 2 pieces, so on-demand splitting must refuse. + const AVG_CHUNK_SIZE: u64 = 1024; + const BLOB_SIZE: usize = 16 * 1024; + + let store_manager = make_chunking_store_manager().await?; + let cas_server = CasServer::new( + &[WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: nativelink_config::cas_server::CasStoreConfig { + cas_store: "main_cas".to_string(), + experimental_chunking: Some(nativelink_config::cas_server::CasChunkingConfig { + index_store: Some("chunk_index".to_string()), + avg_chunk_size_bytes: AVG_CHUNK_SIZE, + max_chunk_count: 2, + }), + }, + }], + &store_manager, + &RemoteCacheCompressionInstances::default(), + )?; + let store = store_manager.get_store("main_cas").unwrap(); + + let mut state = 0x9e37_79b9_u32; + let data: Vec = (0..BLOB_SIZE) + .map(|_| { + state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223); + (state >> 24) as u8 + }) + .collect(); + let blob_digest = Digest { + hash: HASH1.to_string(), + size_bytes: BLOB_SIZE.try_into().unwrap_or(i64::MAX), + }; + store + .update_oneshot( + DigestInfo::try_from(blob_digest.clone())?, + Bytes::from(data), + ) + .await?; + + let status = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest.clone()), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::NotFound); + assert!( + status.message().contains("max_chunk_count"), + "unexpected message: {}", + status.message() + ); + + // Splices above the cap are rejected outright. + let chunk_digest = Digest { + hash: HASH2.to_string(), + size_bytes: 1, + }; + let status = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest), + chunk_digests: vec![chunk_digest.clone(), chunk_digest.clone(), chunk_digest], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await + .unwrap_err(); + assert_eq!(status.code(), Code::InvalidArgument); + assert!( + status.message().contains("expected at most 2"), + "unexpected message: {}", + status.message() + ); + Ok(()) +} + +// Bazel 9.1.1 with --digest_function=blake3 leaves `digest_function` unset in +// SplitBlob/SpliceBlob requests, which is length-ambiguous (SHA256 and +// BLAKE3 are both 32 bytes). The server must infer the function instead of +// assuming the default. +#[nativelink_test] +async fn chunking_infers_blake3_when_digest_function_unset() +-> Result<(), Box> { + const VALUE: &str = "blake3 blob content"; + + let store_manager = make_chunking_store_manager().await?; + let cas_server = make_chunking_cas_server(&store_manager)?; + let store = store_manager.get_store("main_cas").unwrap(); + + let mut hasher = DigestHasherFunc::Blake3.hasher(); + hasher.update(VALUE.as_bytes()); + let blob_digest: Digest = hasher.finalize_digest().into(); + + // Splice: the single chunk is the blob itself, uploaded under its + // BLAKE3 digest, with `digest_function` left unset. + store + .update_oneshot(DigestInfo::try_from(blob_digest.clone())?, VALUE.into()) + .await?; + let splice_response = cas_server + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(blob_digest.clone()), + chunk_digests: vec![blob_digest.clone()], + digest_function: 0, + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(splice_response.blob_digest.as_ref(), Some(&blob_digest)); + + // On-demand split of a fresh blob uploaded whole: the returned chunk + // digests must be BLAKE3 (here a single chunk equal to the blob). + let mut hasher = DigestHasherFunc::Blake3.hasher(); + hasher.update(b"other blake3 content"); + let other_digest: Digest = hasher.finalize_digest().into(); + store + .update_oneshot( + DigestInfo::try_from(other_digest.clone())?, + Bytes::from_static(b"other blake3 content"), + ) + .await?; + let split_response = cas_server + .split_blob(Request::new(SplitBlobRequest { + instance_name: INSTANCE_NAME.to_string(), + blob_digest: Some(other_digest.clone()), + digest_function: 0, + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(split_response.chunk_digests, vec![other_digest]); + Ok(()) +} diff --git a/nativelink-service/tests/data/fastcdc2020_test_vectors.txt b/nativelink-service/tests/data/fastcdc2020_test_vectors.txt new file mode 100644 index 000000000..db89efd7d --- /dev/null +++ b/nativelink-service/tests/data/fastcdc2020_test_vectors.txt @@ -0,0 +1,35 @@ +# Test vectors for the FastCDC 2020 content-defined chunking algorithm +# +# Reference implementations: +# - Rust: https://github.com/nlfiedler/fastcdc-rs +# - Go: https://github.com/buildbuddy-io/fastcdc2020 +# +# Test input: +# Image: https://github.com/nlfiedler/fastcdc-rs/blob/49c3d0b/test/fixtures/SekienAkashita.jpg +# SHA256: d9e749d9367fc908876749d6502eb212fee88c9a94892fb07da5ef3ba8bc39ed +# Size: 109466 bytes +# +# Parameters: +# MinSize: 4096 +# AvgSize: 16384 (must be power of 2) +# MaxSize: 65535 +# Normalization: 2 +# +# Format: offset, length, sha256, fingerprint +# The fingerprint is the 64-bit gear hash value at the chunk boundary. + +# Seed: 0 +0 19186 0f9efa589121d5d9e9e2c4ace91337d77cae866537143f6f15a0ffd525a77c2d 17583755766661134474 +19186 19279 c7c86a165573c16448cda35c9169742e85645af42be22889f8b96b8ee0ec7cb0 4098594969649699419 +38465 17354 bc88521e28a8b4479cdea5f75aa721a24f3a0a7d0be903aa6d505c574e51e89d 2365586132076908760 +55819 16387 4b8dac2652e4685c629d2bb1ae9d4448e676b86f2e67ca0b2fff3d9580184b79 16009206469796846404 +72206 19940 c0a7062da6f2386c28e086ee0cedd5732252741269838773cff1ddb05b2df6ed 2473608525189754172 +92146 17320 7fa5b12134dc75cd2ac8dc60d3a8f3c8d22f0ee9d4cf74a4aa937e2a0d2d79a5 2504464741100432583 + +# Seed: 666 +0 17635 cb3a9d80a3569772d4ed331ca37ab0c862c759897b890fc1aac90a4f2ea3a407 17021115692437263050 +17635 17334 d758c6b7b0b7eef1e996f8ccd17de6c645360b03a26c35541e7581348ac08944 8231525949846907466 +34969 19136 24846aefd89e510594bae3e9d7d5ea5012067601512610fed126a3c57ba993f5 10944310959829698982 +54105 17467 efa785e1fefb49f190e665f72fd246c1442079874508c312196da1fb3040d00b 13602876513398592944 +71572 23593 a2f557bdd8d40d8faada963ad5f91ec54b10ccee7c5ae72754a65137592dc607 2945079350535657389 +95165 14301 e131100b4a7147ccad19dc63c4a2fac1f5d8b644e1373eeb6803825024234efc 8981594897574481255 diff --git a/nativelink-service/tests/execution_server_test.rs b/nativelink-service/tests/execution_server_test.rs index bd2bab9b1..2523402fa 100644 --- a/nativelink-service/tests/execution_server_test.rs +++ b/nativelink-service/tests/execution_server_test.rs @@ -61,7 +61,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; Ok(store_manager) } diff --git a/nativelink-service/tests/fastcdc_conformance_test.rs b/nativelink-service/tests/fastcdc_conformance_test.rs new file mode 100644 index 000000000..5d13c5820 --- /dev/null +++ b/nativelink-service/tests/fastcdc_conformance_test.rs @@ -0,0 +1,152 @@ +// Copyright 2024 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Conformance tests for the `FastCDC` 2020 implementation used by the +//! `SplitBlob` on-demand chunking path against the official REAPI test +//! vectors from the remote-apis repository: +//! +//! +//! The chunk boundaries produced by the server MUST match these vectors +//! byte-for-byte; otherwise chunks produced by clients (e.g. Bazel with +//! `--experimental_remote_cache_chunking`) never deduplicate against chunks +//! produced by the server and the feature silently loses its value. + +use fastcdc::v2020::{AsyncStreamCDC, FastCDC, Normalization}; +use futures::StreamExt; +use nativelink_macro::nativelink_test; +use pretty_assertions::assert_eq; +use sha2::{Digest as _, Sha256}; + +/// The canonical test input named in the vectors file header +/// (SHA256 d9e749d9367fc908876749d6502eb212fee88c9a94892fb07da5ef3ba8bc39ed), +/// shared with the existing `DedupStore` `FastCDC` test fixture. +const TEST_INPUT: &[u8] = include_bytes!("../../nativelink-util/tests/data/SekienAkashita.jpg"); +const TEST_VECTORS: &str = include_str!("data/fastcdc2020_test_vectors.txt"); + +/// Parameters stated in the vectors file header. +const MIN_SIZE: u32 = 4096; +const AVG_SIZE: u32 = 16384; +const MAX_SIZE: u32 = 65535; + +struct ExpectedChunk { + offset: u64, + length: usize, + sha256_hex: String, + fingerprint: u64, +} + +/// Parses the `# Seed: ` sections of the vectors file into +/// (seed, expected chunks) pairs. +fn parse_test_vectors() -> Vec<(u64, Vec)> { + let mut sections = Vec::new(); + for line in TEST_VECTORS.lines() { + let line = line.trim(); + if let Some(seed) = line.strip_prefix("# Seed: ") { + sections.push((seed.parse::().unwrap(), Vec::new())); + continue; + } + if line.is_empty() || line.starts_with('#') { + continue; + } + let mut fields = line.split_whitespace(); + let chunk = ExpectedChunk { + offset: fields.next().unwrap().parse().unwrap(), + length: fields.next().unwrap().parse().unwrap(), + sha256_hex: fields.next().unwrap().to_string(), + fingerprint: fields.next().unwrap().parse().unwrap(), + }; + sections + .last_mut() + .expect("chunk line before any '# Seed:' section") + .1 + .push(chunk); + } + assert!(!sections.is_empty(), "no seed sections parsed"); + sections +} + +#[nativelink_test] +async fn fastcdc2020_matches_reapi_test_vectors() -> Result<(), Box> { + assert_eq!( + hex::encode(Sha256::digest(TEST_INPUT)), + "d9e749d9367fc908876749d6502eb212fee88c9a94892fb07da5ef3ba8bc39ed", + "test fixture does not match the input named in the vectors file" + ); + + for (seed, expected_chunks) in parse_test_vectors() { + let chunks: Vec<_> = FastCDC::with_level_and_seed( + TEST_INPUT, + MIN_SIZE, + AVG_SIZE, + MAX_SIZE, + Normalization::Level2, + seed, + ) + .collect(); + assert_eq!( + chunks.len(), + expected_chunks.len(), + "chunk count mismatch for seed {seed}" + ); + for (chunk, expected) in chunks.iter().zip(&expected_chunks) { + assert_eq!(chunk.offset as u64, expected.offset, "offset, seed {seed}"); + assert_eq!(chunk.length, expected.length, "length, seed {seed}"); + assert_eq!(chunk.hash, expected.fingerprint, "fingerprint, seed {seed}"); + let data = &TEST_INPUT[chunk.offset..chunk.offset + chunk.length]; + assert_eq!( + hex::encode(Sha256::digest(data)), + expected.sha256_hex, + "chunk content sha256, seed {seed}" + ); + } + } + Ok(()) +} + +/// The streaming chunker (the variant `SplitBlob` actually uses) must +/// produce the same boundaries as the in-memory reference. +#[nativelink_test] +async fn fastcdc2020_streaming_matches_reapi_test_vectors() +-> Result<(), Box> { + let sections = parse_test_vectors(); + let (_, expected_chunks) = sections + .iter() + .find(|(seed, _)| *seed == 0) + .expect("seed 0 section missing"); + + let mut cdc = AsyncStreamCDC::with_level( + TEST_INPUT, + MIN_SIZE, + AVG_SIZE, + MAX_SIZE, + Normalization::Level2, + ); + let stream = cdc.as_stream(); + let mut stream = core::pin::pin!(stream); + let mut chunks = Vec::new(); + while let Some(chunk) = stream.next().await { + chunks.push(chunk.expect("chunking the test input failed")); + } + assert_eq!(chunks.len(), expected_chunks.len()); + for (chunk, expected) in chunks.iter().zip(expected_chunks) { + assert_eq!(chunk.offset, expected.offset); + assert_eq!(chunk.length, expected.length); + assert_eq!(chunk.hash, expected.fingerprint); + assert_eq!( + hex::encode(Sha256::digest(&chunk.data)), + expected.sha256_hex + ); + } + Ok(()) +} diff --git a/nativelink-service/tests/fetch_server_test.rs b/nativelink-service/tests/fetch_server_test.rs index f663f7fce..65b431769 100644 --- a/nativelink-service/tests/fetch_server_test.rs +++ b/nativelink-service/tests/fetch_server_test.rs @@ -41,7 +41,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; Ok(store_manager) } diff --git a/nativelink-service/tests/grpc_wire_compression_test.rs b/nativelink-service/tests/grpc_wire_compression_test.rs new file mode 100644 index 000000000..bb0add8c6 --- /dev/null +++ b/nativelink-service/tests/grpc_wire_compression_test.rs @@ -0,0 +1,757 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Integration tests for client-side wire compression in `GrpcStore` +//! (`GrpcSpec.experimental_remote_cache_compression`) against a real +//! compression-enabled `ByteStream`/CAS server. + +use core::sync::atomic::{AtomicI64, AtomicU64, Ordering}; +use std::collections::HashMap; +use std::sync::Arc; + +use bytes::Bytes; +use futures::Future; +use http_body_util::BodyExt; +use hyper_util::rt::TokioIo; +use hyper_util::server::conn::auto; +use hyper_util::service::TowerToHyperService; +use nativelink_config::cas_server::{ByteStreamConfig, CasStoreConfig, WithInstanceName}; +use nativelink_config::stores::{GrpcEndpoint, GrpcSpec, MemorySpec, Retry, StoreType}; +use nativelink_error::{Code, Error}; +use nativelink_macro::nativelink_test; +use nativelink_proto::google::bytestream::{ + QueryWriteStatusRequest, QueryWriteStatusResponse, ReadRequest, ReadResponse, WriteRequest, + WriteResponse, +}; +use nativelink_service::bytestream_server::ByteStreamServer; +use nativelink_service::cas_server::CasServer; +use nativelink_service::wire_compression::RemoteCacheCompressionInstances; +use nativelink_store::grpc_store::GrpcStore; +use nativelink_store::memory_store::MemoryStore; +use nativelink_store::store_manager::StoreManager; +use nativelink_util::background_spawn; +use nativelink_util::common::DigestInfo; +use nativelink_util::store_trait::{Store, StoreLike}; +use sha2::{Digest as ShaDigest, Sha256}; + +const INSTANCE_NAME: &str = ""; + +#[derive(Clone)] +struct Executor; +impl hyper::rt::Executor for Executor +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + fn execute(&self, fut: F) { + background_spawn!("test_executor", fut); + } +} + +async fn start_real_cas_server( + memory_store: Arc, + server_compression_enabled: bool, +) -> Result { + let store_manager = Arc::new(StoreManager::new()); + store_manager.add_store("main_cas", Store::new(memory_store))?; + let compression_instances = if server_compression_enabled { + RemoteCacheCompressionInstances::from_enabled_instance_names([INSTANCE_NAME.to_string()]) + } else { + RemoteCacheCompressionInstances::default() + }; + + let bs_server = ByteStreamServer::new( + &[WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: ByteStreamConfig { + cas_store: "main_cas".to_string(), + ..Default::default() + }, + }], + &store_manager, + &compression_instances, + )?; + let cas_server = CasServer::new( + &[WithInstanceName { + instance_name: INSTANCE_NAME.to_string(), + config: CasStoreConfig { + cas_store: "main_cas".to_string(), + experimental_chunking: None, + }, + }], + &store_manager, + &compression_instances, + )?; + + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let port = listener.local_addr().unwrap().port(); + + let routes = tonic::service::Routes::new(bs_server.into_service()) + .add_service(cas_server.into_service()); + let adapted_service = tower::ServiceBuilder::new() + .map_request(|req: hyper::Request| { + let (parts, body) = req.into_parts(); + let body = body + .map_err(|e| tonic::Status::internal(e.to_string())) + .boxed_unsync(); + hyper::Request::from_parts(parts, body) + }) + .service(routes); + let hyper_service = TowerToHyperService::new(adapted_service); + + background_spawn!("test_server_accept", async move { + loop { + let Ok((stream, _addr)) = listener.accept().await else { + break; + }; + stream.set_nodelay(true).unwrap(); + let hyper_service = hyper_service.clone(); + background_spawn!("test_server_conn", async move { + drop( + auto::Builder::new(Executor) + .serve_connection_with_upgrades(TokioIo::new(stream), hyper_service) + .await, + ); + }); + } + }); + Ok(port) +} + +fn grpc_spec(port: u16, compression: bool) -> GrpcSpec { + GrpcSpec { + instance_name: INSTANCE_NAME.to_string(), + endpoints: vec![GrpcEndpoint { + address: format!("http://127.0.0.1:{port}"), + tls_config: None, + concurrency_limit: None, + connect_timeout_s: 0, + tcp_keepalive_s: 0, + http2_keepalive_interval_s: 0, + http2_keepalive_timeout_s: 0, + }], + store_type: StoreType::Cas, + retry: Retry::default(), + max_concurrent_requests: 0, + connections_per_endpoint: 0, + rpc_timeout_s: 120, + use_legacy_resource_names: false, + headers: HashMap::new(), + forward_headers: vec![], + experimental_read_batching: None, + experimental_remote_cache_compression: Some(compression), + } +} + +/// Structured, ~3:1-compressible content with a real sha256 digest (both +/// wire directions digest-verify). +fn make_content(tag: u8, len: usize) -> (Bytes, DigestInfo) { + let mut data = vec![0u8; len]; + for (i, b) in data.iter_mut().enumerate() { + *b = match i % 8 { + 0..=4 => tag, + 5 => u8::try_from((i / 8) % 256).expect("value is reduced modulo 256"), + _ => u8::try_from((i / 4096) % 256).expect("value is reduced modulo 256"), + }; + } + let mut hasher = Sha256::new(); + hasher.update(&data); + let digest = DigestInfo::try_new(&hex::encode(hasher.finalize()), len).unwrap(); + (Bytes::from(data), digest) +} + +/// Deterministic content that compresses at roughly 4:1 — one pseudo-random +/// byte in every four, constants elsewhere. `make_content` is compressible +/// enough that even multi-megabyte blobs fit in a single 64KiB wire chunk once +/// encoded, which is useless for tests that must interrupt a compressed stream +/// part-way through. +fn make_mixed_content(seed: u64, len: usize) -> (Bytes, DigestInfo) { + let mut state = seed | 1; + let mut data = vec![0u8; len]; + for (i, b) in data.iter_mut().enumerate() { + state = state + .wrapping_mul(6_364_136_223_846_793_005) + .wrapping_add(1_442_695_040_888_963_407); + *b = if i % 4 == 0 { + u8::try_from((state >> 33) & 0xff).expect("masked to a single byte") + } else { + 0x5a + }; + } + let mut hasher = Sha256::new(); + hasher.update(&data); + let digest = DigestInfo::try_new(&hex::encode(hasher.finalize()), len).unwrap(); + (Bytes::from(data), digest) +} + +// A blob above the compression threshold uploads via compressed-blobs and +// must land byte-identical (the server decodes and digest-verifies). +#[nativelink_test] +async fn compressed_upload_round_trip() -> Result<(), Box> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let port = start_real_cas_server(memory_store.clone(), true).await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let (content, digest) = make_content(0xA1, 1024 * 1024); + grpc_store.update_oneshot(digest, content.clone()).await?; + + let stored = memory_store.get_part_unchunked(digest, 0, None).await?; + assert_eq!(stored, content, "decoded upload must be byte-identical"); + Ok(()) +} + +// A full-blob read above the threshold downloads via compressed-blobs; the +// client decodes and digest-verifies. +#[nativelink_test] +async fn compressed_download_round_trip() -> Result<(), Box> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let port = start_real_cas_server(memory_store.clone(), true).await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let (content, digest) = make_content(0xB2, 1024 * 1024); + memory_store.update_oneshot(digest, content.clone()).await?; + + let fetched = grpc_store.get_part_unchunked(digest, 0, None).await?; + assert_eq!(fetched, content, "decoded download must be byte-identical"); + Ok(()) +} + +// Blobs below the threshold must use the identity path: they round-trip +// even against a server with compression disabled. +#[nativelink_test] +async fn small_blob_uses_identity_path() -> Result<(), Box> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let port = start_real_cas_server(memory_store.clone(), false).await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let (content, digest) = make_content(0xC3, 4 * 1024); + grpc_store.update_oneshot(digest, content.clone()).await?; + let fetched = grpc_store.get_part_unchunked(digest, 0, None).await?; + assert_eq!(fetched, content); + Ok(()) +} + +// Ranged reads must use the identity path even above the threshold: they +// round-trip against a compression-disabled server. +#[nativelink_test] +async fn ranged_read_uses_identity_path() -> Result<(), Box> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let compressed_port = start_real_cas_server(memory_store.clone(), true).await?; + let grpc_store = GrpcStore::new(&grpc_spec(compressed_port, true)).await?; + + let (content, digest) = make_content(0xD4, 1024 * 1024); + memory_store.update_oneshot(digest, content.clone()).await?; + + let fetched = grpc_store + .get_part_unchunked(digest, 100, Some(1000)) + .await?; + assert_eq!(fetched, content.slice(100..1100)); + Ok(()) +} + +// A compressed upload to an upstream without compression enabled fails with +// InvalidArgument (config-trust contract, documented on the field). +#[nativelink_test] +async fn upload_to_non_compressed_upstream_fails() -> Result<(), Box> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let port = start_real_cas_server(memory_store.clone(), false).await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let (content, digest) = make_content(0xE5, 1024 * 1024); + let err = grpc_store + .update_oneshot(digest, content) + .await + .expect_err("expected compressed upload to fail against plain upstream"); + assert_eq!(err.code, Code::InvalidArgument, "unexpected error: {err:?}"); + Ok(()) +} + +// Flag off: byte-identical legacy behavior against a plain upstream. +#[nativelink_test] +async fn flag_off_plain_round_trip() -> Result<(), Box> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let port = start_real_cas_server(memory_store.clone(), false).await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, false)).await?; + + let (content, digest) = make_content(0xF6, 1024 * 1024); + grpc_store.update_oneshot(digest, content.clone()).await?; + let fetched = grpc_store.get_part_unchunked(digest, 0, None).await?; + assert_eq!(fetched, content); + Ok(()) +} + +// --------------------------------------------------------------------------- +// Review-round regression tests need a controllable fake ByteStream server +// rather than the real one. +// --------------------------------------------------------------------------- + +#[derive(Debug, Default)] +struct FakeByteStream { + write_calls: Arc, + identity_reads: Arc, + /// Write behavior: consume this many messages, then abort the stream + /// with UNAVAILABLE. Zero means accept-one-then-early-complete (W3). + abort_write_after_messages: Option, + early_complete_write: bool, + /// Read behavior: payload served for compressed-blobs reads. + compressed_read_payload: Option, + /// Hold the compressed read stream open forever after this many chunks. + /// This ensures a decoder error must cancel the feed rather than waiting + /// for the upstream stream to finish. + hold_compressed_read_after_chunks: Option, + /// Fail the compressed read stream with UNAVAILABLE after this many + /// chunks, after letting the decoded prefix settle into the client's + /// writer. Exercises retryable-interruption policy. + abort_compressed_read_after_chunks: Option, + /// Payload served for identity reads (fallback detector). Served honoring + /// `read_offset`/`read_limit` so fallback ranges can be checked exactly. + identity_read_payload: Option, + /// `read_offset`/`read_limit` of the last identity read. Tests that care + /// initialize these to -1 so "never read" is distinguishable from 0. + identity_read_offset: Arc, + identity_read_limit: Arc, +} + +type ReadStreamT = + core::pin::Pin> + Send>>; + +#[tonic::async_trait] +impl nativelink_proto::google::bytestream::byte_stream_server::ByteStream for FakeByteStream { + type ReadStream = ReadStreamT; + + async fn read( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + let request = request.into_inner(); + if request.resource_name.contains("compressed-blobs") { + let payload = self + .compressed_read_payload + .clone() + .ok_or_else(|| tonic::Status::not_found("no compressed payload configured"))?; + let chunks: Vec = payload + .chunks(64 * 1024) + .map(Bytes::copy_from_slice) + .collect(); + let hold_after = self.hold_compressed_read_after_chunks; + let abort_after = self.abort_compressed_read_after_chunks; + let stream = + futures::stream::unfold((chunks, 0usize), move |(chunks, index)| async move { + // Check the hold point before EOF so `hold_after == + // chunks.len()` sends every configured chunk but keeps + // the gRPC stream open instead of reporting EOF. + if Some(index) == hold_after { + futures::future::pending::<()>().await; + } + if index >= chunks.len() { + return None; + } + if Some(index) == abort_after { + // Let the already-sent prefix finish decoding and + // reach the client's writer, so the resume offset + // reflects real forwarded progress. + tokio::time::sleep(core::time::Duration::from_millis(250)).await; + return Some(( + Err(tonic::Status::unavailable( + "injected mid-stream read failure", + )), + (chunks, index), + )); + } + let data = chunks[index].clone(); + Some((Ok(ReadResponse { data }), (chunks, index + 1))) + }); + let boxed: Self::ReadStream = Box::pin(stream); + return Ok(tonic::Response::new(boxed)); + } + self.identity_reads.fetch_add(1, Ordering::Relaxed); + self.identity_read_offset + .store(request.read_offset, Ordering::Relaxed); + self.identity_read_limit + .store(request.read_limit, Ordering::Relaxed); + let payload = self + .identity_read_payload + .clone() + .ok_or_else(|| tonic::Status::not_found("no identity payload configured"))?; + // Honor the requested range like a real server so a resumed read can + // be checked byte-exactly. `read_limit` of zero means "to the end". + let start = usize::try_from(request.read_offset) + .map_err(|_| tonic::Status::invalid_argument("negative read_offset"))? + .min(payload.len()); + let end = if request.read_limit == 0 { + payload.len() + } else { + let limit = usize::try_from(request.read_limit) + .map_err(|_| tonic::Status::invalid_argument("negative read_limit"))?; + start.saturating_add(limit).min(payload.len()) + }; + let payload = payload.slice(start..end); + let chunks: Vec> = payload + .chunks(64 * 1024) + .map(|c| { + Ok(ReadResponse { + data: Bytes::copy_from_slice(c), + }) + }) + .collect(); + let boxed: Self::ReadStream = Box::pin(futures::stream::iter(chunks)); + Ok(tonic::Response::new(boxed)) + } + + async fn write( + &self, + request: tonic::Request>, + ) -> Result, tonic::Status> { + self.write_calls.fetch_add(1, Ordering::Relaxed); + let mut stream = request.into_inner(); + if self.early_complete_write { + // Read exactly one message, then settle the write early per the + // REAPI duplicate-upload contract without consuming the rest. + let _first = stream.message().await?; + return Ok(tonic::Response::new(WriteResponse { committed_size: -1 })); + } + if let Some(abort_after) = self.abort_write_after_messages { + let mut seen = 0u64; + while seen < abort_after { + match stream.message().await? { + Some(_msg) => seen += 1, + None => break, + } + } + return Err(tonic::Status::unavailable("injected mid-stream failure")); + } + Err(tonic::Status::unimplemented("no write behavior configured")) + } + + async fn query_write_status( + &self, + _request: tonic::Request, + ) -> Result, tonic::Status> { + Err(tonic::Status::unimplemented("not used in these tests")) + } +} + +async fn start_fake_bytestream_server(fake: FakeByteStream) -> Result { + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let port = listener.local_addr().unwrap().port(); + let routes = tonic::service::Routes::new( + nativelink_proto::google::bytestream::byte_stream_server::ByteStreamServer::new(fake), + ); + let adapted_service = tower::ServiceBuilder::new() + .map_request(|req: hyper::Request| { + let (parts, body) = req.into_parts(); + let body = body + .map_err(|e| tonic::Status::internal(e.to_string())) + .boxed_unsync(); + hyper::Request::from_parts(parts, body) + }) + .service(routes); + let hyper_service = TowerToHyperService::new(adapted_service); + background_spawn!("fake_server_accept", async move { + loop { + let Ok((stream, _addr)) = listener.accept().await else { + break; + }; + stream.set_nodelay(true).unwrap(); + let hyper_service = hyper_service.clone(); + background_spawn!("fake_server_conn", async move { + drop( + auto::Builder::new(Executor) + .serve_connection_with_upgrades(TokioIo::new(stream), hyper_service) + .await, + ); + }); + } + }); + Ok(port) +} + +// W1: a mid-stream failure of a compressed upload must fail fast with the +// transport error — exactly one write attempt, no resume storm ending in +// InvalidArgument. +#[nativelink_test] +async fn compressed_upload_mid_stream_failure_fails_fast() -> Result<(), Box> +{ + let write_calls = Arc::new(AtomicU64::new(0)); + let port = start_fake_bytestream_server(FakeByteStream { + write_calls: write_calls.clone(), + abort_write_after_messages: Some(2), + ..Default::default() + }) + .await?; + let mut spec = grpc_spec(port, true); + spec.retry = Retry { + max_retries: 3, + delay: 0.01, + ..Default::default() + }; + let grpc_store = GrpcStore::new(&spec).await?; + + let (content, digest) = make_content(0x11, 4 * 1024 * 1024); + let result = grpc_store.update_oneshot(digest, content).await; + let err = result.expect_err("expected mid-stream failure to surface"); + assert_eq!( + err.code, + Code::Unavailable, + "must surface the transport error, not a resume-replay InvalidArgument: {err:?}" + ); + assert_eq!( + write_calls.load(Ordering::Relaxed), + 1, + "compressed uploads must not replay-resume after partial consumption" + ); + Ok(()) +} + +// W2: decoder-detected corruption mid-stream must be terminal +// InvalidArgument deterministically — never silently retried via the +// unverified identity path. +#[nativelink_test] +async fn corrupt_compressed_download_is_terminal() -> Result<(), Box> { + // The decoder must abort MID-STREAM while the feed still has chunks in + // flight (the old classification then saw a cascade "receiver + // disconnected" feed error and silently fell back to the unverified + // identity path). Bit-flips inside a zstd block decode to garbage and + // only fail the digest check at EOF, so instead append a second valid + // frame: its first decoded block overshoots the expected size, which + // the decoder rejects immediately and deterministically. + use nativelink_proto::build::bazel::remote::execution::v2::compressor; + let (content, digest) = make_content(0x22, 8 * 1024 * 1024); + let valid_frame = + nativelink_util::wire_compression::compress(content.clone(), compressor::Value::Zstd)?; + let (extra, _) = make_content(0x99, 8 * 1024 * 1024); + let overflow_frame = + nativelink_util::wire_compression::compress(extra, compressor::Value::Zstd)?; + let mut corrupt = valid_frame.to_vec(); + corrupt.extend_from_slice(&overflow_frame); + let corrupt_chunks = corrupt.len().div_ceil(64 * 1024); + let identity_reads = Arc::new(AtomicU64::new(0)); + let port = start_fake_bytestream_server(FakeByteStream { + identity_reads: identity_reads.clone(), + // Send the complete corrupt payload, but withhold wire EOF. The + // decoder receives enough data to reject the size overshoot while + // the feed remains blocked on the open gRPC stream. + hold_compressed_read_after_chunks: Some(corrupt_chunks), + compressed_read_payload: Some(Bytes::from(corrupt)), + identity_read_payload: Some(content), + ..Default::default() + }) + .await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let result = tokio::time::timeout( + // This only guards against a cancellation deadlock; the decoder's + // size check, rather than this deadline, determines the result. + core::time::Duration::from_secs(10), + grpc_store.get_part_unchunked(digest, 0, None), + ) + .await + .expect("decoder failure must cancel the held compressed read stream"); + let err = result.expect_err("corrupt compressed data must be terminal"); + assert_eq!( + err.code, + Code::InvalidArgument, + "decoder verdict must win over cascade transport classification: {err:?}" + ); + assert_eq!( + identity_reads.load(Ordering::Relaxed), + 0, + "corrupt data must never fall back to the unverified identity path" + ); + Ok(()) +} + +// W3: a server that early-completes a compressed upload while the worker +// producer is still sending must not turn the producer's send/drain into an +// error. +#[nativelink_test] +async fn compressed_upload_returns_after_early_completion() +-> Result<(), Box> { + use nativelink_util::buf_channel::make_buf_channel_pair; + use nativelink_util::store_trait::UploadSizeInfo; + + let port = start_fake_bytestream_server(FakeByteStream { + early_complete_write: true, + ..Default::default() + }) + .await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let (content, digest) = make_content(0x33, 4 * 1024 * 1024); + let (mut tx, rx) = make_buf_channel_pair(); + let producer_content = content.clone(); + let producer = async move { + for chunk in producer_content.chunks(64 * 1024) { + tx.send(Bytes::copy_from_slice(chunk)).await?; + } + tx.send_eof() + }; + let update_fut = grpc_store.update(digest, rx, UploadSizeInfo::ExactSize(content.len() as u64)); + let (result, producer_result) = + tokio::time::timeout(core::time::Duration::from_secs(10), async { + tokio::join!(update_fut, producer) + }) + .await + .expect("early-completed compressed upload must not hang the producer"); + result?; + producer_result?; + Ok(()) +} + +// W4: a retryable compressed-read failure before any output may restart from +// zero through identity. +#[nativelink_test] +async fn compressed_download_failure_before_progress_falls_back_to_identity() +-> Result<(), Box> { + use nativelink_proto::build::bazel::remote::execution::v2::compressor; + + let (content, digest) = make_content(0x44, 1024 * 1024); + let frame = + nativelink_util::wire_compression::compress(content.clone(), compressor::Value::Zstd)?; + let identity_reads = Arc::new(AtomicU64::new(0)); + let identity_read_offset = Arc::new(AtomicI64::new(-1)); + let identity_read_limit = Arc::new(AtomicI64::new(-1)); + let port = start_fake_bytestream_server(FakeByteStream { + identity_reads: identity_reads.clone(), + identity_read_offset: identity_read_offset.clone(), + identity_read_limit: identity_read_limit.clone(), + compressed_read_payload: Some(frame), + abort_compressed_read_after_chunks: Some(0), + identity_read_payload: Some(content.clone()), + ..Default::default() + }) + .await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let fetched = tokio::time::timeout( + core::time::Duration::from_secs(10), + grpc_store.get_part_unchunked(digest, 0, None), + ) + .await + .expect("zero-progress compressed failure must not hang")?; + + assert_eq!( + fetched, content, + "identity fallback must reproduce the blob byte-for-byte" + ); + assert_eq!( + identity_reads.load(Ordering::Relaxed), + 1, + "the zero-progress failure must fall back exactly once" + ); + assert_eq!( + identity_read_offset.load(Ordering::Relaxed), + 0, + "identity fallback must restart from zero" + ); + assert_eq!( + identity_read_limit.load(Ordering::Relaxed), + i64::try_from(content.len())?, + "identity fallback must request exactly the full blob", + ); + Ok(()) +} + +// Once decoded bytes have been forwarded, their digest is still unverified. +// A later transport error must therefore be terminal rather than combining +// that prefix with an identity tail and reporting success. +#[nativelink_test] +async fn corrupt_interrupted_compressed_download_after_progress_is_terminal() +-> Result<(), Box> { + use nativelink_proto::build::bazel::remote::execution::v2::compressor; + + let (content, digest) = make_mixed_content(0x45, 4 * 1024 * 1024); + let (corrupt_content, _) = make_mixed_content(0x46, content.len()); + let frame = + nativelink_util::wire_compression::compress(corrupt_content, compressor::Value::Zstd)?; + let frame_chunks = frame.len().div_ceil(64 * 1024); + assert!( + frame_chunks >= 4, + "test payload must span several wire chunks, got {frame_chunks}" + ); + let identity_reads = Arc::new(AtomicU64::new(0)); + let port = start_fake_bytestream_server(FakeByteStream { + identity_reads: identity_reads.clone(), + compressed_read_payload: Some(frame), + // Two compressed chunks decode to several full zstd blocks. The fake + // waits before failing so that prefix reaches the downstream writer. + abort_compressed_read_after_chunks: Some(2), + identity_read_payload: Some(content), + ..Default::default() + }) + .await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let result = tokio::time::timeout( + core::time::Duration::from_secs(10), + grpc_store.get_part_unchunked(digest, 0, None), + ) + .await + .expect("partial compressed failure must not hang"); + let err = result.expect_err("partial compressed failure must be terminal"); + assert_eq!( + err.code, + Code::Unavailable, + "the original transport error must be preserved: {err:?}" + ); + assert_eq!( + identity_reads.load(Ordering::Relaxed), + 0, + "unverified partial data must never be combined with an identity tail" + ); + Ok(()) +} + +// W5: a download whose consumer goes away must fail, not trigger a pointless +// identity re-read of the remainder into a channel nobody is reading. +#[nativelink_test] +async fn compressed_download_consumer_hangup_does_not_refetch() +-> Result<(), Box> { + use nativelink_proto::build::bazel::remote::execution::v2::compressor; + use nativelink_util::buf_channel::make_buf_channel_pair; + + let (content, digest) = make_content(0x55, 8 * 1024 * 1024); + let frame = + nativelink_util::wire_compression::compress(content.clone(), compressor::Value::Zstd)?; + let identity_reads = Arc::new(AtomicU64::new(0)); + let port = start_fake_bytestream_server(FakeByteStream { + identity_reads: identity_reads.clone(), + compressed_read_payload: Some(frame), + identity_read_payload: Some(content), + ..Default::default() + }) + .await?; + let grpc_store = GrpcStore::new(&grpc_spec(port, true)).await?; + + let (mut writer, reader) = make_buf_channel_pair(); + // Hang up on the read before it can complete. + drop(reader); + let result = tokio::time::timeout( + core::time::Duration::from_secs(10), + grpc_store.get_part(digest, &mut writer, 0, None), + ) + .await + .expect("a hung-up consumer must not hang the read"); + + assert!( + result.is_err(), + "a broken writer must surface as an error, not a silent success" + ); + assert_eq!( + identity_reads.load(Ordering::Relaxed), + 0, + "a writer-side failure must not be retried as an identity read" + ); + Ok(()) +} diff --git a/nativelink-service/tests/push_server_test.rs b/nativelink-service/tests/push_server_test.rs index 066b8b6ea..0ea9a2671 100644 --- a/nativelink-service/tests/push_server_test.rs +++ b/nativelink-service/tests/push_server_test.rs @@ -43,7 +43,7 @@ async fn make_store_manager() -> Result, Error> { None, ) .await?, - ); + )?; Ok(store_manager) } diff --git a/nativelink-service/tests/wire_compression_test.rs b/nativelink-service/tests/wire_compression_test.rs new file mode 100644 index 000000000..8463943cf --- /dev/null +++ b/nativelink-service/tests/wire_compression_test.rs @@ -0,0 +1,270 @@ +// Copyright 2024 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Unit tests for the REAPI wire-compression helpers shared by the +//! `ByteStream` and CAS services: compressor URI resolution, zstd +//! encode/decode with size validation, the zero-copy identity batch-update +//! path, and blocking-pool isolation of the async streaming zstd encoder. + +use core::time::Duration; + +use bytes::Bytes; +use nativelink_error::{Code, Error}; +use nativelink_macro::nativelink_test; +use nativelink_proto::build::bazel::remote::execution::v2::compressor; +use nativelink_service::wire_compression::{ + ZSTD_COMPRESSION_LEVEL, compress, decompress, decompress_batch_update, resolve_wire_compressor, + stream_encode_compressed_download, +}; +use nativelink_util::buf_channel::make_buf_channel_pair; +use nativelink_util::{spawn, spawn_blocking}; +use pretty_assertions::assert_eq; + +#[nativelink_test] +async fn compress_decompress_identity() -> Result<(), Error> { + let data = Bytes::from_static(b"hello world"); + let compressed = compress(data.clone(), compressor::Value::Identity)?; + assert_eq!(compressed, data); + let decompressed = decompress(&compressed, compressor::Value::Identity, data.len())?; + assert_eq!(decompressed, data); + Ok(()) +} + +#[nativelink_test] +async fn compress_decompress_zstd() -> Result<(), Error> { + // Use repetitive data that zstd can actually compress. + let data = Bytes::from("hello world ".repeat(100)); + assert!(data.len() > 1000, "test data should be reasonably large"); + let compressed = compress(data.clone(), compressor::Value::Zstd)?; + // Zstd should compress this repetitive data significantly. + assert!( + compressed.len() < data.len(), + "Zstd compressed {} bytes should be less than original {} bytes", + compressed.len(), + data.len() + ); + let decompressed = decompress(&compressed, compressor::Value::Zstd, data.len())?; + assert_eq!(decompressed, data); + Ok(()) +} + +#[nativelink_test] +async fn decompress_zstd_size_mismatch() -> Result<(), Error> { + let data = Bytes::from_static(b"hello world"); + let compressed = compress(data, compressor::Value::Zstd)?; + let result = decompress(&compressed, compressor::Value::Zstd, 999); + assert_eq!( + result + .expect_err("oversized expected_size must be rejected") + .code, + Code::InvalidArgument + ); + Ok(()) +} + +#[nativelink_test] +async fn decompress_zstd_small_payload_large_claimed_size_is_rejected() -> Result<(), Error> { + // A tiny payload that claims a huge uncompressed size must be rejected + // without pre-allocating the claimed size: `expected_size` is the client's + // digest size and must never be trusted as an allocation hint. The decoder + // bounds output at expected_size and the length check rejects the lie. + let data = Bytes::from_static(b"hello world"); + let compressed = compress(data, compressor::Value::Zstd)?; + let huge_claimed_size = 8 * 1024 * 1024 * 1024; // 8 GiB + let result = decompress(&compressed, compressor::Value::Zstd, huge_claimed_size); + assert_eq!( + result + .expect_err("small payload claiming a huge size must be rejected") + .code, + Code::InvalidArgument + ); + Ok(()) +} + +#[nativelink_test] +async fn decompress_zstd_bomb_exceeding_claimed_size_is_rejected() -> Result<(), Error> { + // A payload that decompresses to MORE than its claimed size (a bomb whose + // digest also lies low) must be rejected. `take(expected_size + 1)` lets + // the decoder produce one byte past the cap so the size check trips instead + // of silently truncating. + let real = Bytes::from("A".repeat(4096)); + let compressed = compress(real, compressor::Value::Zstd)?; + let understated_size = 10; + let result = decompress(&compressed, compressor::Value::Zstd, understated_size); + assert_eq!( + result + .expect_err("output exceeding claimed size must be rejected") + .code, + Code::InvalidArgument + ); + Ok(()) +} + +#[nativelink_test] +async fn decompress_identity_size_mismatch() -> Result<(), Error> { + let result = decompress(b"hello world", compressor::Value::Identity, 999); + assert_eq!( + result + .expect_err("wrong identity size must be rejected") + .code, + Code::InvalidArgument + ); + Ok(()) +} + +#[nativelink_test] +async fn identity_batch_update_keeps_bytes_zero_copy() -> Result<(), Error> { + let data = Bytes::from_static(b"identity batch update payload"); + let original_ptr = data.as_ptr(); + + let decompressed = decompress_batch_update( + data.clone(), + compressor::Value::Identity.into(), + data.len(), + false, + ) + .await?; + + assert_eq!(decompressed, data); + assert_eq!( + decompressed.as_ptr(), + original_ptr, + "identity batch update should validate without copying" + ); + Ok(()) +} + +#[nativelink_test] +async fn resolve_wire_compressor_accepts_only_advertised_compressors() -> Result<(), Error> { + assert_eq!( + resolve_wire_compressor(None, false)?, + compressor::Value::Identity + ); + assert_eq!( + resolve_wire_compressor(Some("identity"), false)?, + compressor::Value::Identity + ); + assert_eq!( + resolve_wire_compressor(Some("zstd"), true)?, + compressor::Value::Zstd + ); + assert!(resolve_wire_compressor(Some("zstd"), false).is_err()); + assert!(resolve_wire_compressor(Some("brotli"), true).is_err()); + Ok(()) +} + +/// A compressed-download encode stream lives at the gRPC CLIENT's drain rate: +/// its output channel only empties as fast as the client reads, and a blob can +/// take arbitrarily long to stream out. If each such stream occupies a tokio +/// blocking-pool thread for its whole lifetime, N concurrent downloads with +/// slow consumers occupy N threads and every unrelated `spawn_blocking` user +/// (filesystem store I/O, upload decode, credential providers) queues behind +/// streams that may not finish for minutes. This test wires up encode streams +/// exactly the way `ByteStreamServer::inner_read_compressed` does, with more +/// held streams than blocking-pool threads, and asserts that a trivial +/// unrelated `spawn_blocking` closure still gets to run. +#[test] +#[expect( + clippy::disallowed_methods, + reason = "the defect under test is blocking-pool capacity, so the test needs \ + a dedicated runtime with a deterministically small blocking pool" +)] +fn held_compressed_download_streams_must_not_starve_blocking_pool() { + // More encode streams than blocking-pool threads. The streams never + // complete during the test: their input never reaches EOF and their + // consumer never reads, so any per-stream thread is held indefinitely. + // The blocking pool schedules FIFO, so if each stream occupies a thread + // the sentinel spawned afterwards can never run — no sleeps or timing + // races are needed for the starvation to be deterministic. + const MAX_BLOCKING_THREADS: usize = 4; + const NUM_STREAMS: usize = 8; + const SENTINEL_TIMEOUT: Duration = Duration::from_secs(2); + const OVERALL_TIMEOUT: Duration = Duration::from_secs(30); + + let runtime = tokio::runtime::Builder::new_multi_thread() + .worker_threads(2) + .max_blocking_threads(MAX_BLOCKING_THREADS) + .enable_all() + .build() + .expect("failed to build test runtime"); + + runtime.block_on(async { + tokio::time::timeout(OVERALL_TIMEOUT, async { + // Held alive for the duration of the sentinel probe: dropping the + // feeders, encode handles, or receivers early would tear the + // streams down and release any held threads. + let mut held_streams = Vec::with_capacity(NUM_STREAMS); + for _ in 0..NUM_STREAMS { + let (mut raw_tx, raw_rx) = make_buf_channel_pair(); + let (compressed_tx, compressed_rx) = make_buf_channel_pair(); + + // Feed incompressible pseudo-random data forever (no EOF) so + // the encoder always has input and keeps producing output. + // The output channel has a small fixed capacity and nothing + // reads `compressed_rx`, so the encoder soon waits on a full + // output channel — the "slow client" that holds the stream + // open. Async sends here mean the feeders themselves never + // occupy blocking-pool threads. + let feeder = spawn!("test_raw_data_feeder", async move { + let mut state = 0x9E37_79B9_7F4A_7C15_u64; + loop { + let mut chunk = vec![0u8; 64 * 1024]; + for word in chunk.chunks_exact_mut(8) { + state = state + .wrapping_mul(6_364_136_223_846_793_005) + .wrapping_add(1_442_695_040_888_963_407); + word.copy_from_slice(&state.to_le_bytes()); + } + if raw_tx.send(Bytes::from(chunk)).await.is_err() { + break; + } + } + }); + + // Start the encode stream the same way + // `ByteStreamServer::inner_read_compressed` does: as a plain + // async future on the runtime, never on the blocking pool. + let encode_task = spawn!( + "test_encode_compressed_download", + stream_encode_compressed_download( + raw_rx, + compressor::Value::Zstd, + ZSTD_COMPRESSION_LEVEL, + compressed_tx, + ) + ); + + held_streams.push((feeder, encode_task, compressed_rx)); + } + + // Unrelated blocking work must not starve behind held + // compressed-download streams. + let sentinel = spawn_blocking!("test_blocking_pool_sentinel", || ()); + let sentinel_result = tokio::time::timeout(SENTINEL_TIMEOUT, sentinel).await; + assert!( + sentinel_result.is_ok(), + "unrelated blocking work must not starve behind {NUM_STREAMS} held \ + compressed-download streams on a {MAX_BLOCKING_THREADS}-thread blocking pool" + ); + + drop(held_streams); + }) + .await + .expect("test exceeded overall timeout"); + }); + + // Encode streams stuck on a full output channel park their blocking-pool + // threads indefinitely; a normal runtime drop would join them and hang. + runtime.shutdown_background(); +} diff --git a/nativelink-store/BUILD.bazel b/nativelink-store/BUILD.bazel index 0911171ad..c3bc47a1a 100644 --- a/nativelink-store/BUILD.bazel +++ b/nativelink-store/BUILD.bazel @@ -33,6 +33,7 @@ rust_library( "src/memory_store.rs", "src/mongo_store.rs", "src/noop_store.rs", + "src/oci_store.rs", "src/ontap_s3_existence_cache_store.rs", "src/ontap_s3_store.rs", "src/r2_store.rs", @@ -66,8 +67,8 @@ rust_library( "@crates//:aws-smithy-runtime-api", "@crates//:aws-smithy-types", "@crates//:azure_core", - "@crates//:azure_storage", - "@crates//:azure_storage_blobs", + "@crates//:azure_identity", + "@crates//:azure_storage_blob", "@crates//:base64", "@crates//:blake3", "@crates//:byteorder", @@ -108,17 +109,25 @@ rust_library( "@crates//:tracing", "@crates//:url", "@crates//:uuid", + "@crates//:webpki-roots", "@crates//:wincode", - ], + ] + select({ + "@platforms//os:macos": ["@crates//:libc"], + "//conditions:default": [], + }), ) rust_test_suite( name = "integration", - timeout = "short", + # "moderate" (300s) rather than "short" (60s): the mongo store test spawns + # a real mongod per test and downloads the MongoDB archive on a cold cache + # (always cold under Bazel's sandboxed $HOME), which straddled the 60s cap. + timeout = "moderate", srcs = [ "tests/ac_utils_test.rs", "tests/azure_blob_store_test.rs", "tests/cache_metrics_store_test.rs", + "tests/common_s3_utils_test.rs", "tests/completeness_checking_store_test.rs", "tests/compression_store_test.rs", "tests/dedup_store_test.rs", @@ -127,9 +136,11 @@ rust_test_suite( "tests/filesystem_store_test.rs", "tests/gcs_client_test.rs", "tests/gcs_store_test.rs", + "tests/grpc_read_batching_test.rs", "tests/grpc_store_test.rs", "tests/memory_store_test.rs", "tests/mongo_store_test.rs", + "tests/oci_store_test.rs", "tests/ontap_s3_existence_cache_store_test.rs", "tests/ontap_s3_store_test.rs", "tests/r2_store_test.rs", @@ -138,6 +149,7 @@ rust_test_suite( "tests/s3_store_test.rs", "tests/shard_store_test.rs", "tests/size_partitioning_store_test.rs", + "tests/store_manager_test.rs", "tests/verify_store_test.rs", ], compile_data = [ @@ -164,8 +176,7 @@ rust_test_suite( "@crates//:aws-smithy-runtime-api", "@crates//:aws-smithy-types", "@crates//:azure_core", - "@crates//:azure_storage", - "@crates//:azure_storage_blobs", + "@crates//:azure_storage_blob", "@crates//:bytes", "@crates//:dirs", "@crates//:flate2", @@ -187,6 +198,7 @@ rust_test_suite( "@crates//:regex", "@crates//:reqwest", "@crates//:rlimit", + "@crates//:rustls", "@crates//:serde_json", "@crates//:serial_test", "@crates//:sha2", diff --git a/nativelink-store/Cargo.toml b/nativelink-store/Cargo.toml index c9c30a3c8..6d96bb385 100644 --- a/nativelink-store/Cargo.toml +++ b/nativelink-store/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-store" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-config = { path = "../nativelink-config" } @@ -28,14 +28,15 @@ aws-smithy-runtime-api = { version = "1.7.4", default-features = false, features aws-smithy-types = { version = "1.3.0", default-features = false, features = [ "http-body-1-x", ] } -azure_core = { version = "0.21.0", default-features = false, features = [ - "hmac_rust", +azure_core = { version = "1", default-features = false, features = [ + "reqwest", + "tokio", ] } -azure_storage = { version = "0.21.0", default-features = false, features = [ - "hmac_rust", +azure_identity = { version = "1", default-features = false, features = [ + "tokio", ] } -azure_storage_blobs = { version = "0.21.0", default-features = false, features = [ - "hmac_rust", +azure_storage_blob = { version = "1", default-features = false, features = [ + "tokio", ] } base64 = { version = "0.22.1", default-features = false, features = ["std"] } blake3 = { version = "1.8.0", default-features = false } @@ -43,12 +44,15 @@ byteorder = { version = "1.5.0", default-features = false } bytes = { version = "1.10.1", default-features = false } const_format = { version = "0.2.34", default-features = false } futures = { version = "0.3.31", default-features = false, features = ["std"] } -gcloud-auth = { version = "=1.2.0", default-features = false, features = [ +gcloud-auth = { version = "1.3", default-features = false, features = [ "jwt-rust-crypto", ] } -gcloud-storage = { version = "1", default-features = false, features = [ +gcloud-storage = { version = "1.3", default-features = false, features = [ "auth", - "rustls-tls", + # reqwest 0.13's `rustls` feature pulls aws-lc-rs; `rustls-no-provider` uses + # the process-default rustls provider (ring, installed by common_s3_utils) so + # the whole binary stays on a single crypto provider. + "rustls-no-provider", ] } hex = { version = "0.4.3", default-features = false } http = { version = "1.3.1", default-features = false } @@ -70,13 +74,13 @@ mongodb = { version = "3", features = [ "compat-3-0-0", "rustls-tls", ], default-features = false } -opentelemetry = { version = "0.30.0", default-features = false } +opentelemetry = { version = "0.32.0", default-features = false } parking_lot = { version = "0.12.3", features = [ "arc_lock", "send_guard", ], default-features = false } patricia_tree = { version = "0.9.0", default-features = false } -prost = { version = "0.13.5", default-features = false } +prost = { version = "0.14.4", default-features = false } rand = { version = "0.9.0", default-features = false, features = [ "thread_rng", ] } @@ -89,8 +93,13 @@ redis = { version = "1.0.0", default-features = false, features = [ "tokio-comp", ] } regex = { version = "1.11.1", default-features = false } -reqwest = { version = "0.12", default-features = false } -reqwest-middleware = { version = "0.4.2", default-features = false } +reqwest = { version = "0.13", default-features = false, features = [ + "charset", + "http2", + "rustls-no-provider", + "stream", +] } +reqwest-middleware = { version = "0.5", default-features = false } rustls = { version = "0.23.27", default-features = false, features = ["ring"] } rustls-pki-types = { version = "1.13.1", default-features = false } serde = { version = "1.0.219", default-features = false } @@ -106,7 +115,7 @@ tokio-stream = { version = "0.1.17", features = [ "fs", ], default-features = false } tokio-util = { version = "0.7.14", default-features = false } -tonic = { version = "0.13.0", features = [ +tonic = { version = "0.14.0", features = [ "tls-ring", "transport", ], default-features = false } @@ -116,11 +125,15 @@ uuid = { version = "1.16.0", default-features = false, features = [ "serde", "v4", ] } +webpki-roots = { version = "1", default-features = false } wincode = { version = "0.5.4", default-features = false, features = [ "alloc", "derive", ] } +[target.'cfg(target_os = "macos")'.dependencies] +libc = { version = "0.2.177", default-features = false } + [dev-dependencies] nativelink-macro = { path = "../nativelink-macro" } diff --git a/nativelink-store/src/azure_blob_store.rs b/nativelink-store/src/azure_blob_store.rs index 689a5e0f5..c01627d1c 100644 --- a/nativelink-store/src/azure_blob_store.rs +++ b/nativelink-store/src/azure_blob_store.rs @@ -19,22 +19,18 @@ use std::borrow::Cow; use std::sync::Arc; use async_trait::async_trait; -use azure_core::auth::Secret; -use azure_core::prelude::Range; -use azure_core::{Body, HttpClient, StatusCode, TransportOptions}; -use azure_storage::StorageCredentials; -use azure_storage_blobs::prelude::*; -use bytes::Bytes; +use azure_core::credentials::TokenCredential; +use azure_core::error::ErrorKind; +use azure_core::http::{RequestContent, RetryOptions, StatusCode, Transport, Url}; +use azure_identity::WorkloadIdentityCredential; +use azure_storage_blob::clients::{BlobContainerClient, BlobContainerClientOptions}; +use azure_storage_blob::models::{ + BlobClientDownloadOptions, BlobClientGetPropertiesResultHeaders, BlockLookupList, HttpRange, + StorageErrorCode, +}; use futures::future::FusedFuture; use futures::stream::{FuturesUnordered, unfold}; use futures::{FutureExt, StreamExt, TryStreamExt}; -use http::Method; -use http_body_util::Full; -use hyper::Uri; -use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; -use hyper_util::client::legacy::Client as LegacyClient; -use hyper_util::client::legacy::connect::HttpConnector as LegacyHttpConnector; -use hyper_util::rt::TokioExecutor; use nativelink_config::stores::ExperimentalAzureSpec; use nativelink_error::{Code, Error, ResultExt, make_err}; use nativelink_metric::MetricsComponent; @@ -46,7 +42,7 @@ use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatus, HealthS use nativelink_util::instant_wrapper::InstantWrapper; use nativelink_util::retry::{Retrier, RetryResult}; use nativelink_util::store_trait::{ - RemoveItemCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, + RemoveCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, }; use tokio::sync::mpsc; use tokio::time::sleep; @@ -73,347 +69,12 @@ const DEFAULT_MAX_RETRY_BUFFER_PER_REQUEST: usize = 5 * 1024 * 1024; // 5 MiB // Default maximum number of concurrent uploads const DEFAULT_MAX_CONCURRENT_UPLOADS: usize = 10; -// Maximum number of idle connections per host -const MAX_IDLE_PER_HOST: usize = 32; - -// Default connection timeout in milliseconds -const DEFAULT_CONNECTION_TIMEOUT_MS: u64 = 3000; - -// Environment variable name for Azure account key -const ACCOUNT_KEY_ENV_VAR: &str = "AZURE_STORAGE_KEY"; - -pub(crate) enum BufferedBodyState { - Buffered(Bytes), - Empty, -} - -pub(crate) struct RequestComponents { - method: Method, - uri: Uri, - version: http::Version, - headers: http::HeaderMap, - body_data: BufferedBodyState, -} - -mod body_processing { - use azure_core::Error; - - use super::{Body, BufferedBodyState}; - - #[inline] - pub(crate) async fn buffer_body(body: Body) -> Result { - match body { - Body::Bytes(bytes) if bytes.is_empty() => Ok(BufferedBodyState::Empty), - Body::Bytes(bytes) => Ok(BufferedBodyState::Buffered(bytes)), - Body::SeekableStream(_) => Err(Error::new( - azure_core::error::ErrorKind::Other, - "Unsupported body type: SeekableStream", - )), - } - } -} - -struct RequestBuilder<'a> { - components: &'a RequestComponents, -} - -impl<'a> RequestBuilder<'a> { - #[inline] - const fn new(components: &'a RequestComponents) -> Self { - Self { components } - } - - #[inline] - fn build(&self) -> Result>, http::Error> { - let mut req_builder = hyper::Request::builder() - .method(self.components.method.clone()) - .uri(self.components.uri.clone()) - .version(self.components.version); - - let headers_map = req_builder.headers_mut().unwrap(); - for (name, value) in &self.components.headers { - headers_map.insert(name, value.clone()); - } - - match &self.components.body_data { - BufferedBodyState::Buffered(bytes) => req_builder.body(Full::new(bytes.clone())), - BufferedBodyState::Empty => req_builder.body(Full::new(Bytes::new())), - } - } -} - -mod conversions { - use std::collections::HashMap; - - use azure_core::{Error, Request, Response, StatusCode, headers as azure_headers}; - use http_body_util::BodyExt; - use hyper::body::Incoming; - - use super::{BufferedBodyState, Method, RequestComponents, Uri, body_processing}; - - pub(crate) trait RequestExt { - async fn into_components(self) -> Result; - } - - impl RequestExt for Request { - async fn into_components(self) -> Result { - let method = Method::from_bytes(self.method().as_ref().as_bytes()).map_err(|e| { - Error::new( - azure_core::error::ErrorKind::Other, - format!("Failed to convert method: {e}"), - ) - })?; - - let uri = Uri::try_from(self.url().as_str()).map_err(|e| { - Error::new( - azure_core::error::ErrorKind::Other, - format!("Failed to parse URI: {e}"), - ) - })?; - - let version = http::Version::HTTP_11; // Default to HTTP/1.1 - - let mut headers = http::HeaderMap::new(); - for (name, value) in self.headers().iter() { - let header_name = - http::HeaderName::from_bytes(name.as_str().as_bytes()).map_err(|e| { - Error::new( - azure_core::error::ErrorKind::Other, - format!("Failed to convert header name: {e}"), - ) - })?; - let header_value = http::HeaderValue::from_str(value.as_str()).map_err(|e| { - Error::new( - azure_core::error::ErrorKind::Other, - format!("Failed to convert header value: {e}"), - ) - })?; - headers.insert(header_name, header_value); - } - - let body = self.body().clone(); - - let needs_buffering = matches!(method, Method::POST | Method::PUT); - - let body_data = if needs_buffering { - body_processing::buffer_body(body).await? - } else { - BufferedBodyState::Empty - }; - - Ok(RequestComponents { - method, - uri, - version, - headers, - body_data, - }) - } - } - - pub(crate) trait ResponseExt { - async fn into_azure_response(self) -> Result; - } +// Default public Azure Blob Storage endpoint suffix. +const DEFAULT_BLOB_ENDPOINT_SUFFIX: &str = "blob.core.windows.net"; - impl ResponseExt for hyper::Response { - async fn into_azure_response(self) -> Result { - let (parts, body) = self.into_parts(); - - // Convert headers - let headers: HashMap<_, _> = parts - .headers - .iter() - .filter_map(|(k, v)| { - Some(( - azure_headers::HeaderName::from(k.as_str().to_owned()), - azure_headers::HeaderValue::from(v.to_str().ok()?.to_owned()), - )) - }) - .collect(); - - let data = body - .collect() - .await - .map_err(|e| { - Error::new( - azure_core::error::ErrorKind::Other, - format!("Failed to collect body: {e}"), - ) - })? - .to_bytes(); - - Ok(Response::new( - StatusCode::try_from(parts.status.as_u16()).expect("Invalid status code"), - azure_headers::Headers::from(headers), - Box::pin(futures::stream::once(futures::future::ready(Ok(data)))), - )) - } - } -} - -mod execution { - use azure_core::Response; - use bytes::Bytes; - use http_body_util::Full; - - use super::conversions::ResponseExt; - use super::{ - Code, HttpsConnector, LegacyClient, LegacyHttpConnector, RequestBuilder, RequestComponents, - RetryResult, fs, make_err, - }; - - pub(crate) async fn execute_request( - client: LegacyClient, Full>, - components: &RequestComponents, - ) -> RetryResult { - let _permit = match fs::get_permit().await { - Ok(permit) => permit, - Err(e) => { - return RetryResult::Retry(make_err!( - Code::Unavailable, - "Failed to acquire permit: {e}" - )); - } - }; - - let request = match RequestBuilder::new(components).build() { - Ok(req) => req, - Err(e) => { - return RetryResult::Err(make_err!( - Code::Internal, - "Failed to create request: {e}", - )); - } - }; - - match client.request(request).await { - Ok(resp) => match resp.into_azure_response().await { - Ok(response) => RetryResult::Ok(response), - Err(e) => RetryResult::Retry(make_err!( - Code::Unavailable, - "Failed to convert response: {e}" - )), - }, - Err(e) => RetryResult::Retry(make_err!( - Code::Unavailable, - "Failed request in AzureBlobStore: {e}" - )), - } - } - - #[inline] - pub(crate) fn create_retry_stream( - client: LegacyClient, Full>, - components: RequestComponents, - ) -> impl futures::Stream> { - futures::stream::unfold(components, move |components| { - let client_clone = client.clone(); - async move { - let result = execute_request(client_clone, &components).await; - Some((result, components)) - } - }) - } -} - -#[derive(Clone)] -pub struct AzureClient { - client: LegacyClient, Full>, - config: Arc, - retrier: Retrier, -} - -impl AzureClient { - pub fn new( - config: ExperimentalAzureSpec, - jitter_fn: Arc Duration + Send + Sync>, - ) -> Result { - let connector = Self::build_connector(&config); - let connection_timeout = if config.connection_timeout_s > 0 { - Duration::from_millis(config.connection_timeout_s) - } else { - Duration::from_millis(DEFAULT_CONNECTION_TIMEOUT_MS) - }; - let client = Self::build_client(connector, connection_timeout); - - Ok(Self { - client, - retrier: Retrier::new( - Arc::new(|duration| Box::pin(sleep(duration))), - jitter_fn, - config.common.retry.clone(), - ), - config: Arc::new(config), - }) - } - - fn build_connector(config: &ExperimentalAzureSpec) -> HttpsConnector { - install_default_rustls_crypto_provider(); - - let builder = HttpsConnectorBuilder::new().with_webpki_roots(); - - let builder_with_schemes = if config.common.insecure_allow_http { - builder.https_or_http() - } else { - builder.https_only() - }; - - if config.common.disable_http2 { - builder_with_schemes.enable_http1().build() - } else { - builder_with_schemes.enable_http1().enable_http2().build() - } - } - - fn build_client( - connector: HttpsConnector, - connection_timeout: Duration, - ) -> LegacyClient, Full> { - LegacyClient::builder(TokioExecutor::new()) - .pool_idle_timeout(connection_timeout) - .pool_max_idle_per_host(MAX_IDLE_PER_HOST) - .build(connector) - } -} - -impl core::fmt::Debug for AzureClient { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("AzureClient") - .field("config", &self.config) - .finish() - } -} - -#[async_trait::async_trait] -impl HttpClient for AzureClient { - async fn execute_request( - &self, - request: &azure_core::Request, - ) -> azure_core::Result { - use conversions::RequestExt; - - let components = request.clone().into_components().await?; - - match self - .retrier - .retry(execution::create_retry_stream( - self.client.clone(), - components, - )) - .await - { - Ok(response) => Ok(response), - Err(e) => Err(azure_core::Error::new( - azure_core::error::ErrorKind::Other, - format!("Connection failed after retries: {e}"), - )), - } - } -} - -#[derive(MetricsComponent, Debug)] +#[derive(MetricsComponent)] pub struct AzureBlobStore { - client: Arc, + client: Arc, now_fn: NowFn, #[metric(help = "The container name for the Azure store")] container: String, @@ -428,6 +89,16 @@ pub struct AzureBlobStore { max_concurrent_uploads: usize, } +impl core::fmt::Debug for AzureBlobStore { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("AzureBlobStore") + .field("container", &self.container) + .field("blob_prefix", &self.blob_prefix) + .field("consider_expired_after_s", &self.consider_expired_after_s) + .finish_non_exhaustive() + } +} + impl AzureBlobStore where I: InstantWrapper, @@ -435,35 +106,80 @@ where { pub async fn new(spec: &ExperimentalAzureSpec, now_fn: NowFn) -> Result, Error> { let jitter_fn = spec.common.retry.make_jitter_fn(); + let client = Self::build_container_client(spec)?; + Self::new_with_client_and_jitter(spec, client, jitter_fn, now_fn) + } - let http_client = Arc::new( - AzureClient::new(spec.clone(), jitter_fn.clone()) - .map_err(|e| make_err!(Code::Unavailable, "Failed to create Azure client: {e}"))?, - ); + /// Builds the container URL and selects the auth strategy: + /// * `sas_url` set -> use it verbatim as the container URL with no credential. + /// * otherwise -> `https://{account}.{endpoint}/{container}` authenticated with + /// Entra ID via Workload Identity (keyless). + fn build_container_client(spec: &ExperimentalAzureSpec) -> Result { + let mut options = BlobContainerClientOptions::default(); + options.client_options.retry = RetryOptions::none(); + // Hand the SDK an HTTP client with an explicit rustls (ring) config. + options.client_options.transport = Some(Self::build_http_transport()?); + + let (container_url, credential): (Url, Option>) = + if let Some(sas_url) = spec.sas_url.as_ref() { + let url = Url::parse(sas_url) + .map_err(|e| make_err!(Code::InvalidArgument, "Invalid Azure sas_url: {e}"))?; + (url, None) + } else { + let endpoint = spec.endpoint.clone().unwrap_or_else(|| { + format!( + "https://{}.{DEFAULT_BLOB_ENDPOINT_SUFFIX}", + spec.account_name + ) + }); + let mut url = Url::parse(&endpoint) + .map_err(|e| make_err!(Code::InvalidArgument, "Invalid Azure endpoint: {e}"))?; + url.path_segments_mut() + .map_err(|()| { + make_err!( + Code::InvalidArgument, + "Azure endpoint is not a valid base URL: {endpoint}" + ) + })? + .pop_if_empty() + .push(&spec.container); + let credential: Arc = WorkloadIdentityCredential::new(None) + .map_err(|e| { + make_err!( + Code::FailedPrecondition, + "Failed to create Azure Workload Identity credential: {e}" + ) + })?; + (url, Some(credential)) + }; - let transport_options = TransportOptions::new(http_client); + BlobContainerClient::new(container_url, credential, Some(options)) + .map_err(|e| make_err!(Code::Unavailable, "Failed to create Azure client: {e}")) + } - let account_key = std::env::var(ACCOUNT_KEY_ENV_VAR).map_err(|e| { - make_err!( - Code::FailedPrecondition, - "Failed to read {ACCOUNT_KEY_ENV_VAR} environment variable: {e}" - ) - })?; + /// Builds an HTTP transport for the Azure SDK backed by a reqwest client with + /// an explicit rustls config using `NativeLink`'s ring crypto provider, so the + /// SDK never falls back to guessing a provider (which breaks HTTPS here). + fn build_http_transport() -> Result { + install_default_rustls_crypto_provider(); - let storage_credentials = - StorageCredentials::access_key(spec.account_name.clone(), Secret::new(account_key)); + let mut roots = rustls::RootCertStore::empty(); + roots.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); + let tls_config = rustls::ClientConfig::builder() + .with_root_certificates(roots) + .with_no_client_auth(); - // Create a container client with the specified credentials and transport - let container_client = BlobServiceClient::builder(&spec.account_name, storage_credentials) - .transport(transport_options) - .container_client(&spec.container); + let client = reqwest::Client::builder() + .use_preconfigured_tls(tls_config) + .build() + .map_err(|e| make_err!(Code::Unavailable, "Failed to build Azure HTTP client: {e}"))?; - Self::new_with_client_and_jitter(spec, container_client, jitter_fn, now_fn) + Ok(Transport::new(Arc::new(client))) } pub fn new_with_client_and_jitter( spec: &ExperimentalAzureSpec, - client: ContainerClient, + client: BlobContainerClient, jitter_fn: Arc Duration + Send + Sync>, now_fn: NowFn, ) -> Result, Error> { @@ -504,44 +220,65 @@ where self.retrier .retry(unfold((), move |state| { let blob_path = blob_path.clone(); + let client = Arc::clone(&self.client); async move { - let result = self.client.blob_client(&blob_path).get_properties().await; + let _permit = match fs::get_permit().await { + Ok(permit) => permit, + Err(e) => { + return Some(( + RetryResult::Retry(make_err!( + Code::Unavailable, + "Failed to acquire permit: {e}" + )), + state, + )); + } + }; + + let result = client.blob_client(&blob_path).get_properties(None).await; match result { Ok(props) => { - if self.consider_expired_after_s > 0 { - let last_modified = props.blob.properties.last_modified; - let now = (self.now_fn)().unix_timestamp() as i64; + if self.consider_expired_after_s > 0 + && let Some(last_modified) = props.last_modified().ok().flatten() + { + let now = (self.now_fn)() + .unix_timestamp() + .try_into() + .unwrap_or(i64::MAX); if last_modified.unix_timestamp() + self.consider_expired_after_s <= now { return Some((RetryResult::Ok(None), state)); } } - let blob_size = props.blob.properties.content_length; + let blob_size = props.content_length().ok().flatten().unwrap_or(0); Some((RetryResult::Ok(Some(blob_size)), state)) } Err(err) => { - if err - .as_http_error() - .is_some_and(|e| e.status() == StatusCode::NotFound) - { + if err.http_status() == Some(StatusCode::NotFound) { + // Distinguish a missing container (a config error) from a + // missing blob (a normal cache miss). + if let ErrorKind::HttpResponse { + error_code: Some(error_code), + .. + } = err.kind() + && error_code == StorageErrorCode::ContainerNotFound.as_ref() + { + return Some(( + RetryResult::Err(make_err!( + Code::InvalidArgument, + "Container not found: {err}" + )), + state, + )); + } Some((RetryResult::Ok(None), state)) - } else if err.to_string().contains("ContainerNotFound") { - Some(( - RetryResult::Err(make_err!( - Code::InvalidArgument, - "Container not found: {}", - err - )), - state, - )) } else { Some(( RetryResult::Retry(make_err!( Code::Unavailable, - "Failed to get blob properties: {:?}", - err + "Failed to get blob properties: {err:?}" )), state, )) @@ -604,7 +341,7 @@ where UploadSizeInfo::ExactSize(sz) | UploadSizeInfo::MaxSize(sz) => sz, }; - // For small files, we'll use single block upload + // For small files of a known size we buffer to `Bytes` and upload in a single request. if max_size < DEFAULT_BLOCK_SIZE && matches!(upload_size, UploadSizeInfo::ExactSize(_)) { let UploadSizeInfo::ExactSize(sz) = upload_size else { unreachable!("upload_size must be UploadSizeInfo::ExactSize here"); @@ -615,67 +352,89 @@ where .err_tip(|| "Could not convert max_retry_buffer_per_request to u64")?, ); - return self.retrier + return self + .retrier .retry(unfold(reader, move |mut reader| { let client = Arc::clone(&self.client); - let blob_client = client.blob_client(&blob_path); + let blob_path = blob_path.clone(); async move { + let _permit = match fs::get_permit().await { + Ok(permit) => permit, + Err(e) => { + return Some(( + RetryResult::Retry(make_err!( + Code::Unavailable, + "Failed to acquire permit: {e}" + )), + reader, + )); + } + }; + let (mut tx, mut rx) = make_buf_channel_pair(); let result = { let reader_ref = &mut reader; let (upload_res, bind_res) = tokio::join!( - async { - let mut buffer = Vec::with_capacity(usize::try_from(sz).expect("size must be non-negative and fit in usize")); - while let Ok(Some(chunk)) = rx.try_next().await { - buffer.extend_from_slice(&chunk); - } + async { + let mut buffer = Vec::with_capacity( + usize::try_from(sz).expect( + "size must be non-negative and fit in usize", + ), + ); + while let Ok(Some(chunk)) = rx.try_next().await { + buffer.extend_from_slice(&chunk); + } - blob_client - .put_block_blob(Body::from(buffer)) - .content_type("application/octet-stream") - .into_future() - .await - .map(|_| ()) - .map_err(|e| make_err!(Code::Aborted, "{:?}", e)) - }, - async { - tx.bind_buffered(reader_ref).await - } - ); + client + .blob_client(&blob_path) + .block_blob_client() + .upload(RequestContent::from(buffer), None) + .await + .map(|_| ()) + .map_err(|e| make_err!(Code::Aborted, "{e:?}")) + }, + async { tx.bind_buffered(reader_ref).await } + ); match (upload_res, bind_res) { - (Ok(size), Ok(())) => Ok(size), + (Ok(()), Ok(())) => Ok(()), (Err(e), _) | (_, Err(e)) => Err(e), } .err_tip(|| "Failed to upload blob in single chunk") }; match result { - Ok(()) => Some((RetryResult::Ok(reader.get_bytes_received()), reader)), + Ok(()) => { + Some((RetryResult::Ok(reader.get_bytes_received()), reader)) + } Err(mut err) => { err.code = Code::Aborted; let bytes_received = reader.get_bytes_received(); if let Err(try_reset_err) = reader.try_reset_stream() { event!( - Level::ERROR, - ?bytes_received, - err = ?try_reset_err, - "Unable to reset stream after failed upload in AzureStore::update" - ); - Some((RetryResult::Err(err - .merge(try_reset_err) - .append(format!("Failed to retry upload with {bytes_received} bytes received in AzureStore::update"))), - reader)) + Level::ERROR, + ?bytes_received, + err = ?try_reset_err, + "Unable to reset stream after failed upload in AzureStore::update" + ); + Some(( + RetryResult::Err(err.merge(try_reset_err).append(format!( + "Failed to retry upload with {bytes_received} bytes received in AzureStore::update" + ))), + reader, + )) } else { - let err = err.append(format!("Retry on upload happened with {bytes_received} bytes received in AzureStore::update")); + let err = err.append(format!( + "Retry on upload happened with {bytes_received} bytes received in AzureStore::update" + )); event!( - Level::INFO, - ?err, - ?bytes_received, - "Retryable Azure error" - ); + Level::INFO, + ?err, + ?bytes_received, + "Retryable Azure error" + ); Some((RetryResult::Retry(err), reader)) } } @@ -685,12 +444,12 @@ where .await; } - // For larger files, we'll use block upload strategy + // For larger files we stream the content as staged blocks and commit a block list. let block_size = cmp::min(max_size / (MAX_BLOCKS as u64 - 1), MAX_BLOCK_SIZE).max(DEFAULT_BLOCK_SIZE); let (tx, mut rx) = mpsc::channel(self.max_concurrent_uploads); - let mut block_ids = Vec::with_capacity(MAX_BLOCKS); + let mut block_ids: Vec> = Vec::with_capacity(MAX_BLOCKS); let retrier = self.retrier.clone(); let read_stream_fut = { @@ -713,32 +472,48 @@ where total_uploaded += write_buf.len() as u64; - let block_id = format!("{block_id:032}"); + // Fixed-width, zero-padded ids keep the committed block list ordered + // after a lexicographic sort. + let block_id = format!("{block_id:032}").into_bytes(); let blob_path = blob_path.clone(); tx.send(async move { self.retrier .retry(unfold( - (write_buf, block_id.clone()), + (write_buf, block_id), move |(write_buf, block_id)| { let client = Arc::clone(&self.client); - let blob_client = client.blob_client(&blob_path); + let blob_path = blob_path.clone(); async move { - let retry_result = blob_client - .put_block( - block_id.clone(), - Body::from(write_buf.clone()), + let _permit = match fs::get_permit().await { + Ok(permit) => permit, + Err(e) => { + return Some(( + RetryResult::Retry(make_err!( + Code::Unavailable, + "Failed to acquire permit: {e}" + )), + (write_buf, block_id), + )); + } + }; + let content_length = write_buf.len() as u64; + let retry_result = client + .blob_client(&blob_path) + .block_blob_client() + .stage_block( + &block_id, + content_length, + RequestContent::from(write_buf.to_vec()), + None, ) - .into_future() .await .map_or_else( |e| { RetryResult::Retry(make_err!( - Code::Aborted, - "Failed to upload block {} in Azure store: {:?}", - block_id, - e - )) + Code::Aborted, + "Failed to upload block in Azure store: {e:?}" + )) }, |_| RetryResult::Ok(block_id.clone()), ); @@ -777,40 +552,61 @@ where } } - // Sorting block IDs to ensure consistent ordering + // Sorting block IDs to ensure consistent ordering of the committed blob. block_ids.sort_unstable(); - // Commit the block list - let block_list = BlockList { - blocks: block_ids - .into_iter() - .map(|id| BlobBlockType::Latest(BlockId::from(id))) - .collect(), + let block_list = BlockLookupList { + latest: Some(block_ids), + ..Default::default() }; retrier .retry(unfold(block_list, move |block_list| { let client = Arc::clone(&self.client); - let blob_client = client.blob_client(&blob_path); + let blob_path = blob_path.clone(); async move { - Some(( - blob_client - .put_block_list(block_list.clone()) - .content_type("application/octet-stream") - .into_future() - .await - .map_or_else( - |e| { - RetryResult::Retry( - Error::from_std_err(Code::Aborted, &e) - .append("Failed to commit block list in Azure store:"), - ) - }, - |_| RetryResult::Ok(total_uploaded), - ), - block_list, - )) + let _permit = match fs::get_permit().await { + Ok(permit) => permit, + Err(e) => { + return Some(( + RetryResult::Retry(make_err!( + Code::Unavailable, + "Failed to acquire permit: {e}" + )), + block_list, + )); + } + }; + + let blocks = match RequestContent::try_from(block_list.clone()) { + Ok(blocks) => blocks, + Err(e) => { + return Some(( + RetryResult::Err(make_err!( + Code::Internal, + "Failed to serialize block list in Azure store: {e:?}" + )), + block_list, + )); + } + }; + + let retry_result = client + .blob_client(&blob_path) + .block_blob_client() + .commit_block_list(blocks, None) + .await + .map_or_else( + |e| { + RetryResult::Retry( + Error::from_std_err(Code::Aborted, &e) + .append("Failed to commit block list in Azure store:"), + ) + }, + |_| RetryResult::Ok(total_uploaded), + ); + Some((retry_result, block_list)) } })) .await @@ -832,66 +628,65 @@ where let blob_path = self.make_blob_path(&key); - let client = Arc::clone(&self.client); - let blob_client = client.blob_client(&blob_path); let range = match length { - Some(len) => Range::new(offset, offset + len - 1), - None => Range::from(offset..), + Some(len) => Some(HttpRange::new(offset, len)), + None if offset == 0 => None, + None => Some(HttpRange::from_offset(offset)), }; self.retrier .retry(unfold(writer, move |writer| { - let range_clone = range.clone(); - let blob_client = blob_client.clone(); + let range = range.clone(); + let client = Arc::clone(&self.client); + let blob_path = blob_path.clone(); async move { - let result = async { - let mut stream = blob_client.get().range(range_clone.clone()).into_stream(); - - while let Some(chunk_result) = stream.next().await { - match chunk_result { - Ok(response) => { - let data = response.data.collect().await.map_err(|e| { - make_err!( - Code::Aborted, - "Failed to collect response data: {:?}", - e - ) - })?; - if data.is_empty() { - continue; - } - writer.send(data).await.map_err(|e| { - make_err!( - Code::Aborted, - "Failed to send data to writer: {:?}", - e - ) - })?; - } - Err(e) => { - return match e { - e if e.as_http_error().is_some_and(|e| { - e.status() == StatusCode::NotFound - }) => - { - Err(make_err!( - Code::NotFound, - "Blob not found in Azure: {:?}", - e - )) - } - _ => Err(make_err!( - Code::Aborted, - "Error reading from Azure stream: {:?}", - e - )), - }; + let _permit = match fs::get_permit().await { + Ok(permit) => permit, + Err(e) => { + return Some(( + RetryResult::Retry(make_err!( + Code::Unavailable, + "Failed to acquire permit: {e}" + )), + writer, + )); + } + }; + + let result: Result<(), Error> = async { + let options = BlobClientDownloadOptions { + range, + ..Default::default() + }; + let response = client + .blob_client(&blob_path) + .download(Some(options)) + .await + .map_err(|e| { + if e.http_status() == Some(StatusCode::NotFound) { + make_err!(Code::NotFound, "Blob not found in Azure: {e:?}") + } else { + make_err!( + Code::Aborted, + "Failed to start download from Azure: {e:?}" + ) } + })?; + + let mut body = response.body; + while let Some(chunk) = body.try_next().await.map_err(|e| { + make_err!(Code::Aborted, "Error reading from Azure stream: {e:?}") + })? { + if chunk.is_empty() { + continue; } + writer.send(chunk).await.map_err(|e| { + make_err!(Code::Aborted, "Failed to send data to writer: {e:?}") + })?; } writer.send_eof().map_err(|e| { - make_err!(Code::Aborted, "Failed to send EOF to writer: {:?}", e) + make_err!(Code::Aborted, "Failed to send EOF to writer: {e:?}") })?; Ok(()) } @@ -928,10 +723,7 @@ where registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { // Azure Blob Storage manages object lifecycle externally, // so we can safely ignore remove callbacks. Ok(()) diff --git a/nativelink-store/src/cache_metrics_store.rs b/nativelink-store/src/cache_metrics_store.rs index 9c3a7933a..deca501d6 100644 --- a/nativelink-store/src/cache_metrics_store.rs +++ b/nativelink-store/src/cache_metrics_store.rs @@ -31,7 +31,7 @@ use nativelink_util::fs; use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatusIndicator}; use nativelink_util::metrics::{CACHE_METRICS, CACHE_TYPE, CacheMetricAttrs}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, StoreOptimizations, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, StoreOptimizations, UploadSizeInfo, }; use opentelemetry::KeyValue; @@ -275,10 +275,7 @@ impl StoreDriver for CacheMetricsStore { self.backend.clone().register_health(registry); } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.backend.register_remove_callback(callback) } } diff --git a/nativelink-store/src/callback_utils.rs b/nativelink-store/src/callback_utils.rs index a18f20c52..29e0783c7 100644 --- a/nativelink-store/src/callback_utils.rs +++ b/nativelink-store/src/callback_utils.rs @@ -14,25 +14,24 @@ use core::borrow::Borrow; use core::pin::Pin; -use std::sync::Arc; use nativelink_util::evicting_map; -use nativelink_util::store_trait::{RemoveItemCallback, StoreKey}; +use nativelink_util::store_trait::{RemoveCallback, StoreKey}; -// Generic struct to hold a RemoveItemCallback ref for the purposes +// Generic struct to hold a RemoveCallback ref for the purposes // of a RemoveStateCallback call #[derive(Debug)] -pub struct RemoveItemCallbackHolder { - callback: Arc, +pub struct RemoveCallbackHolder { + callback: RemoveCallback, } -impl RemoveItemCallbackHolder { - pub fn new(callback: Arc) -> Self { +impl RemoveCallbackHolder { + pub fn new(callback: RemoveCallback) -> Self { Self { callback } } } -impl<'a, Q> evicting_map::RemoveItemCallback for RemoveItemCallbackHolder +impl<'a, Q> evicting_map::RemoveItemCallback for RemoveCallbackHolder where Q: Borrow>, { diff --git a/nativelink-store/src/cas_utils.rs b/nativelink-store/src/cas_utils.rs index 1e2fadde0..7ff289d9e 100644 --- a/nativelink-store/src/cas_utils.rs +++ b/nativelink-store/src/cas_utils.rs @@ -36,7 +36,6 @@ pub const ZERO_BYTE_DIGESTS: [DigestInfo; 2] = [ ), ]; -#[expect(single_use_lifetimes, reason = "false positive")] #[inline] pub fn is_zero_digest<'a>(digest: impl Into>) -> bool { match digest.into() { diff --git a/nativelink-store/src/common_s3_utils.rs b/nativelink-store/src/common_s3_utils.rs index c1c0bd100..c8a9c7410 100644 --- a/nativelink-store/src/common_s3_utils.rs +++ b/nativelink-store/src/common_s3_utils.rs @@ -60,11 +60,24 @@ pub struct TlsClient { impl TlsClient { #[must_use] pub fn new(common: &CommonObjectSpec) -> Self { + Self::new_with_http_support(common, common.insecure_allow_http) + } + + /// Creates a client for AWS credential discovery. + /// + /// The default credential chain uses plain HTTP for link-local metadata + /// services, including the EKS Pod Identity, ECS, and EC2 providers. + #[must_use] + pub fn new_for_credentials(common: &CommonObjectSpec) -> Self { + Self::new_with_http_support(common, true) + } + + fn new_with_http_support(common: &CommonObjectSpec, allow_http: bool) -> Self { install_default_rustls_crypto_provider(); let connector_with_roots = HttpsConnectorBuilder::new().with_platform_verifier(); - let connector_with_schemes = if common.insecure_allow_http { + let connector_with_schemes = if allow_http { connector_with_roots.https_or_http() } else { connector_with_roots.https_only() diff --git a/nativelink-store/src/completeness_checking_store.rs b/nativelink-store/src/completeness_checking_store.rs index a7f81f807..38e054cef 100644 --- a/nativelink-store/src/completeness_checking_store.rs +++ b/nativelink-store/src/completeness_checking_store.rs @@ -29,7 +29,7 @@ use nativelink_util::common::DigestInfo; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::metrics_utils::CounterWithTime; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use parking_lot::Mutex; use tokio::sync::Notify; @@ -398,10 +398,7 @@ impl StoreDriver for CompletenessCheckingStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.ac_store.register_remove_callback(callback.clone())?; self.cas_store.register_remove_callback(callback)?; Ok(()) diff --git a/nativelink-store/src/compression_store.rs b/nativelink-store/src/compression_store.rs index ab85d320d..9e6e52327 100644 --- a/nativelink-store/src/compression_store.rs +++ b/nativelink-store/src/compression_store.rs @@ -30,7 +30,7 @@ use nativelink_util::buf_channel::{ use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::spawn; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use serde::{Deserialize, Serialize}; use wincode::{SchemaRead, SchemaWrite}; @@ -288,7 +288,38 @@ impl StoreDriver for CompressionStore { digests: &[StoreKey<'_>], results: &mut [Option], ) -> Result<(), Error> { - self.inner_store.has_with_results(digests, results).await + if !digests.iter().any(|digest| is_zero_digest(digest.borrow())) { + return self.inner_store.has_with_results(digests, results).await; + } + + for (digest, result) in digests.iter().zip(results.iter_mut()) { + if is_zero_digest(digest.borrow()) { + *result = Some(0); + } + } + + let nonzero_digests = digests + .iter() + .filter(|digest| !is_zero_digest(digest.borrow())) + .map(StoreKey::borrow) + .collect::>(); + if nonzero_digests.is_empty() { + return Ok(()); + } + + let mut nonzero_results = vec![None; nonzero_digests.len()]; + self.inner_store + .has_with_results(&nonzero_digests, &mut nonzero_results) + .await?; + for (result, inner_result) in digests + .iter() + .zip(results.iter_mut()) + .filter_map(|(digest, result)| (!is_zero_digest(digest.borrow())).then_some(result)) + .zip(nonzero_results) + { + *result = inner_result; + } + Ok(()) } async fn update( @@ -297,6 +328,16 @@ impl StoreDriver for CompressionStore { mut reader: DropCloserReadHalf, upload_size: UploadSizeInfo, ) -> Result { + if is_zero_digest(key.borrow()) { + return reader.recv().await.and_then(|should_be_empty| { + if should_be_empty.is_empty() { + Ok(0) + } else { + Err(make_err!(Code::Internal, "Zero byte hash not empty")) + } + }); + } + let mut output_state = UploadState::new(&self, upload_size)?; let (mut tx, rx) = make_buf_channel_pair(); @@ -667,10 +708,7 @@ impl StoreDriver for CompressionStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.inner_store.register_remove_callback(callback) } } diff --git a/nativelink-store/src/dedup_store.rs b/nativelink-store/src/dedup_store.rs index bde8ed7c5..d37850f8d 100644 --- a/nativelink-store/src/dedup_store.rs +++ b/nativelink-store/src/dedup_store.rs @@ -27,7 +27,7 @@ use nativelink_util::common::DigestInfo; use nativelink_util::fastcdc::FastCDC; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use serde::{Deserialize, Serialize}; use tokio_util::codec::FramedRead; @@ -396,10 +396,7 @@ impl StoreDriver for DedupStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.index_store .register_remove_callback(callback.clone())?; self.content_store.register_remove_callback(callback)?; diff --git a/nativelink-store/src/default_store_factory.rs b/nativelink-store/src/default_store_factory.rs index 6dfdbde3e..01ae9d064 100644 --- a/nativelink-store/src/default_store_factory.rs +++ b/nativelink-store/src/default_store_factory.rs @@ -36,6 +36,7 @@ use crate::grpc_store::GrpcStore; use crate::memory_store::MemoryStore; use crate::mongo_store::ExperimentalMongoStore; use crate::noop_store::NoopStore; +use crate::oci_store::OciStore; use crate::ontap_s3_existence_cache_store::OntapS3ExistenceCache; use crate::ontap_s3_store::OntapS3Store; use crate::r2_store::R2Store; @@ -77,6 +78,9 @@ pub fn store_factory<'a>( ExperimentalCloudObjectSpec::R2(r2_config) => { R2Store::new(r2_config, SystemTime::now).await? } + ExperimentalCloudObjectSpec::Oci(oci_config) => { + OciStore::new(oci_config, SystemTime::now).await? + } }, StoreSpec::RedisStore(spec) => { if spec.mode == RedisMode::Cluster { diff --git a/nativelink-store/src/existence_cache_store.rs b/nativelink-store/src/existence_cache_store.rs index a26b5796e..ffd2625f1 100644 --- a/nativelink-store/src/existence_cache_store.rs +++ b/nativelink-store/src/existence_cache_store.rs @@ -29,7 +29,7 @@ use nativelink_util::evicting_map::{EvictingMap, LenEntry}; use nativelink_util::health_utils::{HealthStatus, HealthStatusIndicator}; use nativelink_util::instant_wrapper::InstantWrapper; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use parking_lot::Mutex; use tracing::{debug, info, trace}; @@ -312,10 +312,7 @@ impl StoreDriver for ExistenceCacheStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.inner_store.register_remove_callback(callback) } } diff --git a/nativelink-store/src/fast_slow_store.rs b/nativelink-store/src/fast_slow_store.rs index d7ae49a05..a6e9d28b1 100644 --- a/nativelink-store/src/fast_slow_store.rs +++ b/nativelink-store/src/fast_slow_store.rs @@ -33,14 +33,17 @@ use nativelink_util::buf_channel::{ }; use nativelink_util::fs; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; +use nativelink_util::metrics::{record_store_tier_io, record_store_tier_read}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, StoreOptimizations, - UploadSizeInfo, slow_update_store_with_file, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, StoreOptimizations, UploadSizeInfo, + slow_update_store_with_file, }; use parking_lot::Mutex; use tokio::sync::OnceCell; use tracing::{debug, info, trace, warn}; +use crate::filesystem_store::FilesystemStore; + // TODO(palfrey) This store needs to be evaluated for more efficient memory usage, // there are many copies happening internally. @@ -211,6 +214,32 @@ impl FastSlowStore { &self.slow_store } + /// Returns the filesystem-backed tiers that can evict a digest. + /// + /// The worker's fast store is normally a `FilesystemStore`, while the slow + /// store may be one behind a `RefStore`. `Store::downcast_ref` follows + /// wrappers that delegate `inner_store`; transforming wrappers intentionally + /// keep themselves visible because their digest-to-bytes mapping may differ, + /// so they are not recursively inspected here. + pub fn get_filesystem_stores(&self) -> Vec> { + let mut stores = Vec::with_capacity(2); + for store in [&self.fast_store, &self.slow_store] { + let Some(filesystem_store) = store + .downcast_ref::(None) + .and_then(FilesystemStore::get_arc) + else { + continue; + }; + if !stores + .iter() + .any(|existing| Arc::ptr_eq(existing, &filesystem_store)) + { + stores.push(filesystem_store); + } + } + stores + } + pub fn get_arc(&self) -> Option> { self.weak_self.upgrade() } @@ -274,7 +303,7 @@ impl FastSlowStore { if let StoreKey::Digest(d) = key.borrow() { err.with_context(ErrorContext::MissingDigest { hash: d.packed_hash().to_string(), - size: d.size_bytes() as i64, + size: d.size_bytes().try_into().unwrap_or(i64::MAX), }) } else { err @@ -308,6 +337,7 @@ impl FastSlowStore { self.metrics .slow_store_hit_count .fetch_add(1, Ordering::Acquire); + record_store_tier_read("slow", "hit"); counted_hit = true; } @@ -316,6 +346,7 @@ impl FastSlowStore { self.metrics .slow_store_downloaded_bytes .fetch_add(output_buf_len, Ordering::Acquire); + record_store_tier_io("slow", "read", output_buf_len); let writer_fut = Self::calculate_range( &(bytes_received..bytes_received + output_buf_len), @@ -769,7 +800,13 @@ impl StoreDriver for FastSlowStore { // `has()` can report a stale map entry whose file is gone, so // get_part may still return NotFound; fall through to the slow // store unless we have already streamed bytes to the caller. - if self.fast_store.has(key.borrow()).await?.is_some() { + // One existence check, reused: this is the hot read path and `has()` + // on a filesystem fast store is a syscall. + let in_fast_store = self.fast_store.has(key.borrow()).await?.is_some(); + if !in_fast_store { + record_store_tier_read("fast", "miss"); + } + if in_fast_store { let bytes_before = writer.get_bytes_written(); match self .fast_store @@ -783,6 +820,8 @@ impl StoreDriver for FastSlowStore { self.metrics .fast_store_downloaded_bytes .fetch_add(writer.get_bytes_written(), Ordering::Acquire); + record_store_tier_read("fast", "hit"); + record_store_tier_io("fast", "read", writer.get_bytes_written()); return Ok(()); } Err(e) @@ -791,6 +830,7 @@ impl StoreDriver for FastSlowStore { self.metrics .fast_store_stale_map_falls_through .fetch_add(1, Ordering::Acquire); + record_store_tier_read("fast", "stale"); warn!(%key, ?e, "Stale fast-store map entry; falling through to slow store"); // fall through to populate path } @@ -815,6 +855,8 @@ impl StoreDriver for FastSlowStore { self.metrics .slow_store_downloaded_bytes .fetch_add(writer.get_bytes_written(), Ordering::Acquire); + record_store_tier_read("slow", "hit"); + record_store_tier_io("slow", "read", writer.get_bytes_written()); return Ok(()); } @@ -835,6 +877,8 @@ impl StoreDriver for FastSlowStore { self.metrics .slow_store_downloaded_bytes .fetch_add(writer.get_bytes_written(), Ordering::Acquire); + record_store_tier_read("slow", "hit"); + record_store_tier_io("slow", "read", writer.get_bytes_written()); return Ok(()); } @@ -928,10 +972,7 @@ impl StoreDriver for FastSlowStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.fast_store.register_remove_callback(callback.clone())?; self.slow_store.register_remove_callback(callback)?; Ok(()) diff --git a/nativelink-store/src/filesystem_store.rs b/nativelink-store/src/filesystem_store.rs index 3624e17c7..2a4831b3a 100644 --- a/nativelink-store/src/filesystem_store.rs +++ b/nativelink-store/src/filesystem_store.rs @@ -43,8 +43,10 @@ use nativelink_util::fs::FileSlot; use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatus, HealthStatusIndicator}; #[cfg(unix)] use nativelink_util::spawn_blocking; +#[cfg(unix)] +use nativelink_util::store_trait::RemoveItemCallback; use nativelink_util::store_trait::{ - RemoveItemCallback, StoreDriver, StoreKey, StoreKeyBorrow, StoreOptimizations, UploadSizeInfo, + RemoveCallback, StoreDriver, StoreKey, StoreKeyBorrow, StoreOptimizations, UploadSizeInfo, }; use tokio::io::{AsyncReadExt, AsyncWriteExt, Take}; use tokio::sync::Semaphore; @@ -52,7 +54,7 @@ use tokio::time::timeout; use tokio_stream::wrappers::ReadDirStream; use tracing::{debug, error, info, trace, warn}; -use crate::callback_utils::RemoveItemCallbackHolder; +use crate::callback_utils::RemoveCallbackHolder; use crate::cas_utils::is_zero_digest; // Default size to allocate memory of the buffer when reading files. @@ -67,7 +69,9 @@ pub const DIGEST_FOLDER: &str = "d"; /// **executable** (0o555) variants of CAS blobs (see /// [`FilesystemStore::get_executable_hardlink_source`]). It is a sibling of /// `content_path` rather than a child so the normal content/temp scan and prune -/// logic never touches it. Cleared on startup; entries are regenerable. +/// logic never touches it. Cleared on writable startup; entries are +/// regenerable. If the wipe is blocked by a read-only filesystem, executable +/// variants are disabled so surviving files are never trusted. #[cfg(unix)] const EXECUTABLE_DIR_SUFFIX: &str = ".exec"; @@ -376,6 +380,272 @@ pub fn make_temp_key(key: &StoreKey) -> StoreKey<'static> { StoreKey::Digest(make_temp_digest(key.borrow().into_digest())) } +/// Group-commit flush coalescer (macOS only). +/// +/// On macOS, `File::sync_all` issues `fcntl(F_FULLFSYNC)` — a full +/// device-cache flush — once per call. The flush is serialized at the +/// device, costs multiple milliseconds, and dominates uploads of many +/// small blobs (a 4,400-tiny-file action input tree spends ~12s of its +/// ~14.5s materialization in these flushes). Linux does not have this +/// problem because concurrent `fsync` calls coalesce inside the +/// filesystem journal's group commit. +/// +/// This applies the same group-commit idea in userspace, exploiting an +/// asymmetry in `F_FULLFSYNC`: writing a file's pages to the storage +/// device is per-file work (plain `fsync(2)`, cheap), while the expensive +/// device-cache drain is device-wide by nature. Each writer first pushes +/// its own data to the device with `fsync(2)`, then joins the current +/// commit round; a single long-lived flusher task per DEVICE issues one +/// `F_FULLFSYNC` (on a dedicated sentinel file) per round, covering every +/// previously-`fsync`ed blob at once. Rounds self-batch exactly like a +/// journal: while one flush is running, later writers accumulate into +/// the next round. +/// +/// The coalescer (and its flusher task) is per store instance. Sharing +/// one coalescer across all stores on a device would amortize further — +/// the flush is device-wide — but a process-global flusher task cannot +/// safely outlive the tokio runtime that spawned it (multiple runtimes +/// coexist in one process, e.g. one per test); doing this correctly +/// needs a runtime-agnostic flusher (a dedicated OS thread) and is left +/// as a follow-up. +/// +/// Durability is identical to per-file `F_FULLFSYNC`: a writer only +/// proceeds (and only renames its blob into the content directory) after +/// a device-cache flush that started after its own `fsync(2)` completed. +#[cfg(target_os = "macos")] +#[derive(Debug)] +struct FlushCoalescer { + /// The round currently accepting waiters. Swapped out by the flusher + /// right before it flushes, so writers whose `fsync(2)` finished + /// after the flush began land in the next round. + current_round: parking_lot::Mutex>, + /// Wakes the flusher task. Writers notify after subscribing to their + /// round, so a wakeup can never be observed before its waiter. + wake: Arc, + /// Dedicated file the `F_FULLFSYNC` is issued on. A SIBLING of the + /// store's content path (like the `.exec` variant directory), so + /// neither the startup scan nor `move_old_cache`'s legacy root sweep + /// ever sees it. + sentinel: Arc, + /// Number of device-wide barriers issued. Kept separately from the + /// per-file `fsync(2)` count so tests can pin the coalescing invariant. + full_flush_count: Arc, +} + +#[cfg(target_os = "macos")] +#[derive(Debug)] +struct FlushRound { + /// Broadcasts the flush outcome to every writer in the round. + result_tx: tokio::sync::watch::Sender>>, +} + +#[cfg(target_os = "macos")] +impl FlushRound { + fn new() -> Arc { + let (result_tx, _) = tokio::sync::watch::channel(None); + Arc::new(Self { result_tx }) + } +} + +/// Guarantees a [`FlushRound`]'s waiters always receive a result: if the +/// flusher task is cancelled at an await point (runtime shutdown), waiters +/// must get an error rather than pend forever — their own `Arc` +/// keeps the channel alive, so a dropped-sender wakeup can never happen. +#[cfg(target_os = "macos")] +struct SendOnDrop(Option>); + +#[cfg(target_os = "macos")] +impl SendOnDrop { + fn finish(mut self, result: Result<(), Error>) { + if let Some(round) = self.0.take() { + // Ignore send errors: every waiter may have been cancelled. + drop(round.result_tx.send(Some(result))); + } + } +} + +#[cfg(target_os = "macos")] +impl Drop for SendOnDrop { + fn drop(&mut self) { + if let Some(round) = self.0.take() { + drop(round.result_tx.send(Some(Err(make_err!( + Code::Internal, + "Flush coalescer round task cancelled before completing" + ))))); + } + } +} + +#[cfg(target_os = "macos")] +impl Drop for FlushCoalescer { + fn drop(&mut self) { + // Wake the flusher so it observes the dead Weak and exits instead + // of parking forever. + self.wake.notify_one(); + } +} + +#[cfg(target_os = "macos")] +impl FlushCoalescer { + /// Creates the coalescer for a store and spawns its flusher task on + /// the current runtime (the same runtime the store's uploads run on). + async fn for_content_path(content_path: &str) -> Result, Error> { + // Sibling of `content_path` (never inside it): the startup scan + // and `move_old_cache` sweep everything under the content root. + let sentinel_path = format!("{content_path}.flush_sentinel"); + let sentinel = spawn_blocking!("filesystem_store_flush_sentinel_open", move || { + std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(false) + .open(&sentinel_path) + .map_err(|e| { + make_err!( + Code::Internal, + "Failed to create flush sentinel {sentinel_path}: {e:?}" + ) + }) + }) + .await + .err_tip(|| "Failed to join flush sentinel open task")??; + + let coalescer = Arc::new(Self { + current_round: parking_lot::Mutex::new(FlushRound::new()), + wake: Arc::new(tokio::sync::Notify::new()), + sentinel: Arc::new(sentinel), + full_flush_count: Arc::new(AtomicU64::new(0)), + }); + + let weak = Arc::downgrade(&coalescer); + let wake = coalescer.wake.clone(); + background_spawn!("filesystem_store_flush_coalescer", async move { + loop { + wake.notified().await; + let Some(coalescer) = weak.upgrade() else { + return; + }; + coalescer.flush_one_round().await; + // Drop the strong ref before parking so the store can be + // torn down while the flusher is idle. + } + }); + Ok(coalescer) + } + + /// Waits until a device-cache flush that started after this call has + /// completed. Callers must have already `fsync(2)`ed their own file. + async fn commit(&self) -> Result<(), Error> { + let round = self.current_round.lock().clone(); + let mut result_rx = round.result_tx.subscribe(); + // Notify strictly after subscribing: the flusher skips rounds + // with no receivers, so this ordering makes lost wakeups + // impossible (a permit is stored even while the flusher is busy). + self.wake.notify_one(); + let result_ref = result_rx + .wait_for(Option::is_some) + .await + .map_err(|_| make_err!(Code::Internal, "Flush coalescer round dropped"))?; + result_ref + .clone() + .unwrap_or_else(|| Err(make_err!(Code::Internal, "Flush round result missing"))) + } + + async fn flush_one_round(&self) { + let round = self.current_round.lock().clone(); + if round.result_tx.receiver_count() == 0 { + // Spurious wakeup (e.g. a permit left over from a round that + // a previous iteration already served). + return; + } + let send_guard = SendOnDrop(Some(round.clone())); + + // Brief accumulation window, only when this round actually has + // multiple waiters: lets a burst pack more writers into the round + // before it closes, trading ~3ms of publish latency (about the + // cost of one device flush) for fewer device flushes. A solo + // writer on an idle store skips it and pays only its own flush. + if round.result_tx.receiver_count() > 1 { + tokio::time::sleep(Duration::from_millis(3)).await; + } + // Close the round: writers arriving from here on cannot assume + // this flush covers them, so they must get a fresh round. + { + let mut current = self.current_round.lock(); + if Arc::ptr_eq(&*current, &round) { + *current = FlushRound::new(); + } + } + let sentinel = self.sentinel.clone(); + let full_flush_count = self.full_flush_count.clone(); + let flush_result = spawn_blocking!("filesystem_store_full_flush", move || { + use std::os::fd::AsRawFd; + use std::os::unix::fs::FileExt; + // Keep the sentinel dirty so the flush is never a no-op. + // Best-effort: a failed write (e.g. ENOSPC on a full CoW + // volume) must not fail the whole round — the fcntl below is + // what provides the device-cache drain. + if let Err(err) = sentinel.write_at(b"f", 0) { + warn!(?err, "Flush sentinel write failed; issuing flush anyway"); + } + // Count the actual blocking operation, rather than merely counting + // rounds scheduled by the async task. + full_flush_count.fetch_add(1, Ordering::Relaxed); + loop { + if unsafe { libc::fcntl(sentinel.as_raw_fd(), libc::F_FULLFSYNC) } != -1 { + return Ok(()); + } + let err = std::io::Error::last_os_error(); + // std's sync_all retries EINTR (cvt_r); match it. + if err.kind() != std::io::ErrorKind::Interrupted { + return Err(Error::from(err).append("F_FULLFSYNC failed in flush coalescer")); + } + } + }) + .await + .unwrap_or_else(|e| { + Err(Error::from_std_err(Code::Internal, &e).append("Flush coalescer task failed")) + }); + send_guard.finish(flush_result); + } +} + +#[cfg(unix)] +async fn prepare_executable_dir(content_path: &str) -> Result { + fn is_non_writable_error(err: &std::io::Error) -> bool { + matches!( + err.kind(), + std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ReadOnlyFilesystem + ) + } + + let executable_dir = format!("{content_path}{EXECUTABLE_DIR_SUFFIX}"); + let executable_digest_dir = format!("{executable_dir}/{DIGEST_FOLDER}"); + spawn_blocking!("filesystem_store_prepare_executable_dir", move || { + match std::fs::remove_dir_all(&executable_dir) { + Ok(()) => {} + Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} + // A read-only cache must remain available for ordinary reads. Do + // not reuse the directory, though: a surviving executable variant + // may be stale or torn after an unclean shutdown. + Err(err) if is_non_writable_error(&err) => return Ok(false), + Err(err) => { + return Err(Error::from(err) + .append(format!("Failed to clear executable dir {executable_dir}"))); + } + } + + match std::fs::create_dir_all(&executable_digest_dir) { + Ok(()) => Ok(true), + Err(err) if is_non_writable_error(&err) => Ok(false), + Err(err) => Err(Error::from(err).append(format!( + "Failed to create executable dir {executable_digest_dir}" + ))), + } + }) + .await + .err_tip(|| "Failed to join executable-dir preparation task")? +} + impl LenEntry for FileEntryImpl { #[inline] fn len(&self) -> u64 { @@ -476,7 +746,7 @@ pub fn key_from_file(file_name: &str, file_type: FileType) -> Result = - EvictingMap, Arc, SystemTime, RemoveItemCallbackHolder>; + EvictingMap, Arc, SystemTime, RemoveCallbackHolder>; async fn add_files_to_cache( evicting_map: &FsEvictingMap<'_, Fe>, @@ -786,6 +1056,50 @@ where Ok(false) } +/// Deletes a digest's `.exec` variant (see +/// [`FilesystemStore::get_executable_hardlink_source`]) when that digest is +/// evicted or replaced in the primary CAS `evicting_map`. Without this, the +/// `.exec` directory is invisible to `max_bytes` and is only ever cleared by +/// the startup `remove_dir_all`, so it grows without bound at runtime (#2474). +/// Tying its lifetime to the primary entry instead bounds total disk use to +/// roughly `2 * max_bytes` in the worst case (every blob also executable). +#[cfg(unix)] +#[derive(Debug)] +struct ExecutableVariantRemover { + content_path: String, +} + +#[cfg(unix)] +impl RemoveItemCallback for ExecutableVariantRemover { + fn callback<'a>( + &'a self, + store_key: StoreKey<'a>, + ) -> Pin + Send + 'a>> { + Box::pin(async move { + let StoreKey::Digest(digest) = store_key else { + return; + }; + let variant_path = format!( + "{}{EXECUTABLE_DIR_SUFFIX}/{DIGEST_FOLDER}/{digest}", + self.content_path + ); + match fs::remove_file(&variant_path).await { + Ok(()) => debug!( + ?variant_path, + "Deleted executable variant for evicted digest" + ), + // Common case: no variant was ever materialized for this digest. + Err(err) if err.code == Code::NotFound => {} + Err(err) => warn!( + ?variant_path, + ?err, + "Failed to delete executable variant for evicted digest" + ), + } + }) + } +} + #[derive(Debug, MetricsComponent)] pub struct FilesystemStore { #[metric] @@ -796,16 +1110,31 @@ pub struct FilesystemStore { block_size: u64, #[metric(help = "Size of the configured read buffer size")] read_buffer_size: usize, + /// See [`FilesystemSpec::evict_page_cache`]. When false (the default) the + /// per-blob `posix_fadvise(DONTNEED)` calls are skipped. + evict_page_cache: bool, weak_self: Weak, rename_fn: fn(&OsStr, &OsStr) -> Result<(), std::io::Error>, /// Limits concurrent write operations to prevent disk I/O saturation. write_semaphore: Option, + /// See [`FlushCoalescer`]: amortizes the per-blob `F_FULLFSYNC` cost + /// across concurrent uploads without weakening durability. `None` when + /// the sentinel could not be created (e.g. read-only content volume); + /// uploads then fall back to per-file `sync_all`, matching the old + /// behavior (and such stores fail at write time anyway). + #[cfg(target_os = "macos")] + flush_coalescer: Option>, /// Per-digest single-flight locks guarding creation of the executable /// variant in `{content_path}.exec`, so each variant's writable fd is /// opened exactly once. The outer lock is sync and only ever held to /// get/insert/remove the per-digest async lock — never across I/O. #[cfg(unix)] executable_locks: std::sync::Mutex>>>, + /// False when the startup wipe could not safely remove old executable + /// variants from a read-only filesystem. Ordinary CAS reads remain + /// available, but executable hardlink sources must not reuse stale files. + #[cfg(unix)] + executable_variants_enabled: bool, } impl FilesystemStore { @@ -839,18 +1168,33 @@ impl FilesystemStore { // Executable-variant directory: a sibling of `content_path` holding // per-digest 0o555 copies used as hardlink sources for executable - // inputs (see `get_executable_hardlink_source`). Cleared on startup — - // the variants are regenerable and we never want a stale one to leak - // across runs. Unix-only: the executable bit (and the ETXTBSY race it - // guards against) does not apply on Windows. + // inputs (see `get_executable_hardlink_source`). Cleared on writable + // startup — the variants are regenerable and we never want a stale one + // to leak across runs. If a read-only filesystem prevents the wipe, + // ordinary CAS reads remain enabled but executable variants do not. + // Unix-only: the executable bit (and the ETXTBSY race it guards + // against) does not apply on Windows. #[cfg(unix)] - { - let executable_dir = format!("{}{EXECUTABLE_DIR_SUFFIX}", spec.content_path); - drop(fs::remove_dir_all(&executable_dir).await); - fs::create_dir_all(format!("{executable_dir}/{DIGEST_FOLDER}")) - .await - .err_tip(|| format!("Failed to create executable dir {executable_dir}"))?; - } + let executable_variants_enabled = { + let enabled = prepare_executable_dir(&spec.content_path).await?; + if !enabled { + warn!( + executable_dir = %format!("{}{EXECUTABLE_DIR_SUFFIX}", spec.content_path), + "Executable directory is not writable; serving CAS reads with executable variants disabled" + ); + } + if enabled { + // Only register cleanup when executable variants are enabled. + // Otherwise surviving variants are deliberately quarantined, + // and repeated deletion warnings would obscure the fallback. + evicting_map.add_remove_callback(RemoveCallbackHolder::new(Arc::new( + ExecutableVariantRemover { + content_path: spec.content_path.clone(), + }, + ))); + } + enabled + }; let shared_context = Arc::new(SharedContext { active_drop_spawns: AtomicU64::new(0), @@ -883,16 +1227,35 @@ impl FilesystemStore { } else { None }; + // Never make construction fail over the durability optimization: + // a read-only content volume must still serve reads, exactly as + // it did before the coalescer existed. + #[cfg(target_os = "macos")] + let flush_coalescer = FlushCoalescer::for_content_path(&shared_context.content_path) + .await + .inspect_err(|err| { + warn!( + ?err, + "Failed to create flush coalescer; falling back to per-file sync_all" + ); + }) + .ok(); + Ok(Arc::new_cyclic(|weak_self| Self { shared_context, evicting_map, block_size, read_buffer_size, + evict_page_cache: spec.evict_page_cache, weak_self: weak_self.clone(), rename_fn, write_semaphore, + #[cfg(target_os = "macos")] + flush_coalescer, #[cfg(unix)] executable_locks: std::sync::Mutex::new(HashMap::new()), + #[cfg(unix)] + executable_variants_enabled, })) } @@ -900,6 +1263,20 @@ impl FilesystemStore { self.weak_self.upgrade() } + /// Reserve a digest before it is populated so active action inputs cannot + /// be evicted while they are being materialized. + pub fn lease_digest(&self, digest: &DigestInfo) { + let key: StoreKey<'static> = (*digest).into(); + self.evicting_map.lease_key(StoreKeyBorrow::from(key)); + } + + /// Release a batch of action-input leases and trim retained entries once. + pub async fn release_digests(&self, digests: &[DigestInfo]) { + self.evicting_map + .release_keys(digests.iter().map(|digest| StoreKey::Digest(*digest))) + .await; + } + /// Path of the read-only executable (0o555) variant for `digest`. #[cfg(unix)] fn executable_variant_path(&self, digest: &DigestInfo) -> OsString { @@ -931,6 +1308,12 @@ impl FilesystemStore { &self, digest: &DigestInfo, ) -> Result { + if !self.executable_variants_enabled { + return Err(make_err!( + Code::FailedPrecondition, + "Executable hardlink sources are disabled because the startup wipe could not safely clear the read-only executable directory" + )); + } let variant_path = self.executable_variant_path(digest); // Fast path: the variant already exists, so the caller can hardlink it @@ -962,6 +1345,24 @@ impl FilesystemStore { } let result = self.create_executable_variant(digest, &variant_path).await; + + // The digest may have been evicted mid-copy: its eviction callback ran + // before the rename published the variant, so nothing owns the file + // anymore. This orphans the variant from eviction accounting, but the + // race is rare enough (needs an eviction to land in the narrow window + // between rename and this check, on a digest's first-ever variant + // materialization) that it's a self-limiting leak, not a systemic one + // — cheaper to log and let this action succeed with the still-valid + // file than to fail an otherwise-successful action over it. + if result.is_ok() && self.evicting_map.get(&digest.into()).await.is_none() { + warn!( + %digest, + ?variant_path, + "Digest evicted while materializing its executable variant; \ + variant is now untracked by eviction accounting" + ); + } + // Drop the per-digest lock entry regardless of outcome so the map // cannot grow unbounded; a concurrent waiter already cloned the Arc. self.forget_executable_lock(digest); @@ -1030,10 +1431,33 @@ impl FilesystemStore { "executable-variant chmod 0o555 failed: {e:?}" ) })?; - // Reopen read-only purely to fsync the bytes durable before publish. + // Belt-and-suspenders flush before publish. The `.exec` + // directory is cleared before executable variants are enabled, + // so durability is not needed across process restarts. The + // flush still ensures a published variant is complete for the + // current process. Non-macOS keeps the prior `sync_all` + // behavior; macOS uses plain `fsync(2)` (data handed to the + // device, no multi-ms `F_FULLFSYNC` device-cache drain), which + // covers kernel panics — the next writable startup wipe covers + // power loss. let f = std::fs::File::open(&temp_owned) .map_err(|e| make_err!(Code::Internal, "executable-variant reopen: {e:?}"))?; - f.sync_all() + #[cfg(target_os = "macos")] + let flush_result = { + use std::os::fd::AsRawFd; + loop { + if unsafe { libc::fsync(f.as_raw_fd()) } == 0 { + break Ok(()); + } + let err = std::io::Error::last_os_error(); + if err.kind() != std::io::ErrorKind::Interrupted { + break Err(err); + } + } + }; + #[cfg(not(target_os = "macos"))] + let flush_result = f.sync_all(); + flush_result .map_err(|e| make_err!(Code::Internal, "executable-variant fsync: {e:?}"))?; drop(f); rename_fn(temp_owned.as_os_str(), variant_owned.as_os_str()).map_err(|e| { @@ -1106,15 +1530,15 @@ impl FilesystemStore { .flush() .await .err_tip(|| "Failed to flush in filesystem store")?; - temp_file - .as_ref() - .sync_all() + self.flush_durably(&temp_file) .await - .err_tip(|| "Failed to sync_data in filesystem store")?; + .err_tip(|| "Failed to sync in filesystem store")?; drop(permit); - temp_file.advise_dontneed(); + if self.evict_page_cache { + temp_file.advise_dontneed(); + } trace!(?temp_file, "Dropping file to update_file"); drop(temp_file); @@ -1224,6 +1648,7 @@ impl FilesystemStore { .await; return Err(err); } + trace!(?key, "Finished emplace file"); encoded_file_path.path_type = PathType::Content; encoded_file_path.key = key; Ok(()) @@ -1232,6 +1657,61 @@ impl FilesystemStore { .err_tip(|| "Failed to create spawn in filesystem store update_file")? } + /// Makes `file`'s contents durable with `sync_all` semantics. + /// + /// On macOS the naive equivalent (`fcntl(F_FULLFSYNC)` per file) is a + /// full device-cache flush that serializes at the device and dominates + /// many-small-blob uploads, so the flush is split into the cheap + /// per-file part (`fsync(2)`: push this file's pages to the device) + /// and a device-wide cache drain shared with every concurrent upload + /// via [`FlushCoalescer`]. Other platforms get their journal's group + /// commit for free and keep plain `sync_all`. + async fn flush_durably(&self, file: &FileSlot) -> Result<(), Error> { + #[cfg(target_os = "macos")] + { + use std::os::fd::AsRawFd; + let Some(flush_coalescer) = &self.flush_coalescer else { + return file.as_ref().sync_all().await.map_err(Into::into); + }; + // Dup the handle so the blocking task owns its own fd: if + // this future is cancelled mid-await, the temp file's fd can + // close and be reused, and an already-started blocking task + // must never fsync an unrelated descriptor. + let file_dup = file + .as_ref() + .try_clone() + .await + .err_tip(|| "Failed to dup fd for fsync in filesystem store")? + .into_std() + .await; + // Deliberately NOT via `fs::call_with_permit`: the caller's + // `FileSlot` already holds an open-file permit, so requiring a + // second one here deadlocks when the semaphore is drained (the + // exact scenario the #2051 regression test pins at one + // permit). Concurrency is still bounded: every in-flight fsync + // belongs to an upload holding a `FileSlot` permit. + spawn_blocking!("filesystem_store_fsync", move || { + loop { + if unsafe { libc::fsync(file_dup.as_raw_fd()) } == 0 { + return Ok(()); + } + let err = std::io::Error::last_os_error(); + // std's sync_all retries EINTR (cvt_r); match it. + if err.kind() != std::io::ErrorKind::Interrupted { + return Err(Error::from(err).append("fsync failed in filesystem store")); + } + } + }) + .await + .err_tip(|| "Failed to join fsync task in filesystem store")??; + flush_coalescer.commit().await + } + #[cfg(not(target_os = "macos"))] + { + file.as_ref().sync_all().await.map_err(Into::into) + } + } + pub fn get_eviction_snapshot(&self) -> EvictionSnapshot { self.evicting_map.get_snapshot() } @@ -1241,6 +1721,16 @@ impl FilesystemStore { self.evicting_map.clone() } + /// Returns the number of device-wide durability barriers issued by this + /// store's macOS flush coalescer. Exposed so the integration test can pin + /// the batching behavior rather than only checking data correctness. + #[cfg(target_os = "macos")] + pub fn full_flush_count_for_test(&self) -> Option { + self.flush_coalescer + .as_ref() + .map(|coalescer| coalescer.full_flush_count.load(Ordering::Relaxed)) + } + // Separated out so tests can use this pub async fn make_temp_file( &self, @@ -1370,15 +1860,15 @@ impl StoreDriver for FilesystemStore { .flush() .await .err_tip(|| "Failed to flush in filesystem store update_oneshot")?; - temp_file - .as_ref() - .sync_all() + self.flush_durably(&temp_file) .await - .err_tip(|| "Failed to sync_data in filesystem store update_oneshot")?; + .err_tip(|| "Failed to sync in filesystem store update_oneshot")?; drop(_permit); - temp_file.advise_dontneed(); + if self.evict_page_cache { + temp_file.advise_dontneed(); + } drop(temp_file); *entry.data_size_mut() = data.len() as u64; @@ -1417,7 +1907,9 @@ impl StoreDriver for FilesystemStore { // We are done with the file, if we hold a reference to the file here, it could // result in a deadlock if `emplace_file()` also needs file descriptors. trace!(?file, "Dropping file to to update_with_whole_file"); - file.advise_dontneed(); + if self.evict_page_cache { + file.advise_dontneed(); + } drop(file); self.emplace_file(key.into_owned(), Arc::new(entry)) .await @@ -1481,7 +1973,9 @@ impl StoreDriver for FilesystemStore { .await .err_tip(|| "Failed to send chunk in filesystem store get_part")?; } - temp_file.get_ref().advise_dontneed(); + if self.evict_page_cache { + temp_file.get_ref().advise_dontneed(); + } writer .send_eof() .err_tip(|| "Filed to send EOF in filesystem store get_part")?; @@ -1505,12 +1999,9 @@ impl StoreDriver for FilesystemStore { registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.evicting_map - .add_remove_callback(RemoveItemCallbackHolder::new(callback)); + .add_remove_callback(RemoveCallbackHolder::new(callback)); Ok(()) } } diff --git a/nativelink-store/src/gcs_client/client.rs b/nativelink-store/src/gcs_client/client.rs index 5e812ea7a..d8e374862 100644 --- a/nativelink-store/src/gcs_client/client.rs +++ b/nativelink-store/src/gcs_client/client.rs @@ -216,7 +216,7 @@ impl GcsClient { /// Convert GCS object to our internal representation fn convert_to_gcs_object(&self, obj: Object) -> GcsObject { let update_time = obj.updated.map(|dt| Timestamp { - seconds: dt.unix_timestamp(), + seconds: dt.unix_timestamp() as u64, nanos: 0, }); diff --git a/nativelink-store/src/gcs_client/mocks.rs b/nativelink-store/src/gcs_client/mocks.rs index ee4662691..f5ba13b55 100644 --- a/nativelink-store/src/gcs_client/mocks.rs +++ b/nativelink-store/src/gcs_client/mocks.rs @@ -151,12 +151,12 @@ impl MockGcsOperations { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() - .as_secs() as i64; + .as_secs(); let metadata = GcsObject { name: path.path.clone(), bucket: path.bucket.clone(), - size: content.len() as i64, + size: content.len().try_into().unwrap_or(i64::MAX), content_type: DEFAULT_CONTENT_TYPE.to_string(), update_time: Some(Timestamp { seconds: now, @@ -244,14 +244,14 @@ impl MockGcsOperations { &self, path: &ObjectPath, content: Vec, - timestamp: i64, + timestamp: u64, ) { let object_key = self.get_object_key(path); let metadata = GcsObject { name: path.path.clone(), bucket: path.bucket.clone(), - size: content.len() as i64, + size: content.len().try_into().unwrap_or(i64::MAX), content_type: DEFAULT_CONTENT_TYPE.to_string(), update_time: Some(Timestamp { seconds: timestamp, @@ -264,11 +264,11 @@ impl MockGcsOperations { } /// Get the current timestamp - fn get_current_timestamp(&self) -> i64 { + fn get_current_timestamp(&self) -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap_or_default() - .as_secs() as i64 + .as_secs() } } @@ -450,7 +450,7 @@ impl GcsOperations for MockGcsOperations { // Update metadata if this is the final chunk if total_size.is_some_and(|size| size == end_offset) { - mock_object.metadata.size = mock_object.content.len() as i64; + mock_object.metadata.size = mock_object.content.len().try_into().unwrap_or(i64::MAX); mock_object.metadata.update_time = Some(Timestamp { seconds: self.get_current_timestamp(), nanos: 0, diff --git a/nativelink-store/src/gcs_client/types.rs b/nativelink-store/src/gcs_client/types.rs index ab667c443..94350f4fc 100644 --- a/nativelink-store/src/gcs_client/types.rs +++ b/nativelink-store/src/gcs_client/types.rs @@ -48,8 +48,8 @@ pub struct GcsObject { #[derive(Debug, Clone, Copy)] pub struct Timestamp { - pub seconds: i64, - pub nanos: i32, + pub seconds: u64, + pub nanos: u32, } #[derive(Clone, Debug)] diff --git a/nativelink-store/src/gcs_store.rs b/nativelink-store/src/gcs_store.rs index 247ced282..dd9731a5c 100644 --- a/nativelink-store/src/gcs_store.rs +++ b/nativelink-store/src/gcs_store.rs @@ -30,7 +30,7 @@ use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatus, HealthS use nativelink_util::instant_wrapper::InstantWrapper; use nativelink_util::retry::{Retrier, RetryResult}; use nativelink_util::store_trait::{ - RemoveItemCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, + RemoveCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, }; use rand::Rng; use tokio::time::{sleep, timeout}; @@ -53,7 +53,7 @@ pub struct GcsStore { key_prefix: String, retrier: Retrier, #[metric(help = "The number of seconds to consider an object expired")] - consider_expired_after_s: i64, + consider_expired_after_s: u64, #[metric(help = "The number of bytes to buffer for retrying requests")] max_retry_buffer_size: usize, #[metric(help = "The size of chunks for resumable uploads")] @@ -137,7 +137,7 @@ where jitter_fn, spec.common.retry.clone(), ), - consider_expired_after_s: i64::from(spec.common.consider_expired_after_s), + consider_expired_after_s: u64::from(spec.common.consider_expired_after_s), max_retry_buffer_size, max_chunk_size, max_concurrent_uploads: max_connections, @@ -162,7 +162,7 @@ where if consider_expired_after_s != 0 && let Some(update_time) = &metadata.update_time { - let now_s = now_fn().unix_timestamp() as i64; + let now_s = now_fn().unix_timestamp(); if update_time.seconds + consider_expired_after_s <= now_s { return Some((RetryResult::Ok(None), object_path)); } @@ -429,15 +429,24 @@ where .await { Ok(stream) => stream, - Err(e) if e.code == Code::NotFound => { - return Some((RetryResult::Err(e), (offset, writer))); - } + // NotFound is intentionally not special-cased here: + // the retrier doesn't retry NotFound by default, but + // emitting `Retry` lets `retry.retry_on_errors` opt + // reads into retrying read-after-write races where + // an object is still finalizing or being repopulated. Err(e) => return Some((RetryResult::Retry(e), (offset, writer))), }; while let Some(next_chunk) = stream.next().await { match next_chunk { Ok(bytes) => { + // HTTP/2 peers may emit zero-length DATA frames + // (e.g. a bare END_STREAM frame), which surface + // here as empty chunks. `send()` rejects empty + // buffers by contract, so skip them. + if bytes.is_empty() { + continue; + } offset += bytes.len() as u64; if let Err(err) = writer.send(bytes).await { return Some((RetryResult::Err(err), (offset, writer))); @@ -473,10 +482,7 @@ where registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { // As we're backed by GCS, this store doesn't actually drop stuff // so we can actually just ignore this Ok(()) diff --git a/nativelink-store/src/grpc_store.rs b/nativelink-store/src/grpc_store.rs index 40edc4dc0..87910f727 100644 --- a/nativelink-store/src/grpc_store.rs +++ b/nativelink-store/src/grpc_store.rs @@ -13,15 +13,17 @@ // limitations under the License. use core::pin::Pin; +use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use core::time::Duration; use std::borrow::Cow; -use std::sync::Arc; +use std::collections::{HashMap, VecDeque}; +use std::sync::{Arc, Weak}; use async_trait::async_trait; -use bytes::BytesMut; +use bytes::{Bytes, BytesMut}; use futures::stream::{FuturesUnordered, unfold}; use futures::{Future, Stream, StreamExt, TryFutureExt, TryStreamExt, future}; -use nativelink_config::stores::GrpcSpec; +use nativelink_config::stores::{GrpcReadBatchingConfig, GrpcSpec}; use nativelink_error::{Error, ResultExt, error_if, make_err}; use nativelink_metric::MetricsComponent; use nativelink_proto::build::bazel::remote::execution::v2::action_cache_client::ActionCacheClient; @@ -29,35 +31,44 @@ use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_s use nativelink_proto::build::bazel::remote::execution::v2::{ ActionResult, BatchReadBlobsRequest, BatchReadBlobsResponse, BatchUpdateBlobsRequest, BatchUpdateBlobsResponse, FindMissingBlobsRequest, FindMissingBlobsResponse, - GetActionResultRequest, GetTreeRequest, GetTreeResponse, UpdateActionResultRequest, + GetActionResultRequest, GetTreeRequest, GetTreeResponse, SpliceBlobRequest, SpliceBlobResponse, + SplitBlobRequest, SplitBlobResponse, UpdateActionResultRequest, batch_update_blobs_request, + compressor, }; use nativelink_proto::google::bytestream::byte_stream_client::ByteStreamClient; use nativelink_proto::google::bytestream::{ QueryWriteStatusRequest, QueryWriteStatusResponse, ReadRequest, ReadResponse, WriteRequest, WriteResponse, }; -use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; +use nativelink_util::buf_channel::{ + DropCloserReadHalf, DropCloserWriteHalf, make_buf_channel_pair, +}; use nativelink_util::common::DigestInfo; use nativelink_util::connection_manager::ConnectionManager; use nativelink_util::digest_hasher::{DigestHasherFunc, default_digest_hasher_func}; use nativelink_util::health_utils::HealthStatusIndicator; use nativelink_util::proto_stream_utils::{ - FirstStream, WriteRequestStreamWrapper, WriteState, WriteStateWrapper, + FirstStream, MAX_WRITE_REQUEST_DATA_BYTES, WriteRequestStreamWrapper, WriteState, + WriteStateWrapper, }; use nativelink_util::resource_info::ResourceInfo; use nativelink_util::retry::{Retrier, RetryResult}; -use nativelink_util::store_trait::{RemoveItemCallback, StoreDriver, StoreKey, UploadSizeInfo}; +use nativelink_util::store_trait::{RemoveCallback, StoreDriver, StoreKey, UploadSizeInfo}; use nativelink_util::telemetry::ClientHeaders; -use nativelink_util::{default_health_status_indicator, tls_utils}; +use nativelink_util::wire_compression::{ + stream_decode_compressed_upload, stream_encode_compressed_download_from_reader, +}; +use nativelink_util::{background_spawn, default_health_status_indicator, tls_utils}; use opentelemetry::context::Context; use opentelemetry::global; use opentelemetry::propagation::Injector; use parking_lot::Mutex; use prost::Message; +use tokio::sync::{Semaphore, oneshot}; use tokio::time::sleep; use tonic::metadata::{Ascii, MetadataKey, MetadataValue}; use tonic::{Code, IntoRequest, Request, Response, Status, Streaming}; -use tracing::{error, trace, warn}; +use tracing::{debug, error, trace, warn}; use uuid::Uuid; struct TonicMetadataInjector<'a>(&'a mut tonic::metadata::MetadataMap); @@ -104,9 +115,138 @@ fn enrich_request( request } +/// Minimum blob size for wire compression when +/// `experimental_remote_cache_compression` is enabled. Below this, zstd +/// framing overhead and per-blob CPU outweigh the wire savings (small blobs +/// are the batching paths' domain). +const WIRE_COMPRESSION_MIN_SIZE_BYTES: u64 = 64 * 1024; + +/// Zstd level for `GrpcStore`'s own compressed transfers. Level 1: measured on +/// artifact-shaped corpora, higher levels bought no meaningful wire reduction +/// while encoding slower, and internal hops are throughput-sensitive. +const WIRE_COMPRESSION_ZSTD_LEVEL: i32 = 1; + +/// Estimated per-entry protobuf and framing overhead charged against +/// `max_batch_bytes`, so that batches of many tiny blobs cannot push a +/// `BatchReadBlobs` response over the gRPC message size limit. +const BATCH_READ_PER_ENTRY_OVERHEAD_BYTES: u64 = 256; + +/// A small-blob read waiting to be coalesced into a `BatchReadBlobs` RPC. +#[derive(Debug)] +struct PendingRead { + digest: DigestInfo, + digest_function: i32, + tx: oneshot::Sender>, +} + +/// The pending small-blob reads plus the total payload bytes they declare. +#[derive(Debug, Default)] +struct ReadQueue { + items: VecDeque, + bytes: u64, +} + +/// State for coalescing small-blob reads into `BatchReadBlobs` RPCs. +/// +/// This uses a slot-based group commit scheme: callers enqueue their read and +/// then try to start a detached dispatcher task by acquiring one of +/// `dispatch_slots` semaphore permits. A dispatcher repeatedly drains up to +/// `max_batch_bytes` worth of pending reads into a single `BatchReadBlobs` +/// request until the queue is empty. This is work-conserving (a read never +/// waits while a dispatch slot is free) and uses no timers. +#[derive(Debug, MetricsComponent)] +struct ReadBatcher { + max_blob_size_bytes: u64, + max_batch_bytes: u64, + max_queued_bytes: u64, + queue: Mutex, + dispatch_slots: Arc, + #[metric(help = "Number of BatchReadBlobs RPCs sent by the read coalescer")] + batches_sent: AtomicU64, + #[metric(help = "Number of blob reads coalesced into BatchReadBlobs RPCs")] + blobs_batched: AtomicU64, + #[metric( + help = "Number of reads that bypassed batching because the queue byte budget was full" + )] + queue_bypasses: AtomicU64, + #[metric(help = "Number of batched reads that resolved to a per-entry error")] + batched_read_errors: AtomicU64, + #[metric(help = "Payload bytes currently waiting in the read coalescer queue")] + queued_bytes: AtomicU64, +} + +impl ReadBatcher { + fn new(config: &GrpcReadBatchingConfig) -> Self { + Self { + max_blob_size_bytes: config.max_blob_size_bytes, + max_batch_bytes: config.max_batch_bytes, + max_queued_bytes: config.max_queued_bytes, + queue: Mutex::new(ReadQueue::default()), + dispatch_slots: Arc::new(Semaphore::new(config.dispatch_slots)), + batches_sent: AtomicU64::new(0), + blobs_batched: AtomicU64::new(0), + queue_bypasses: AtomicU64::new(0), + batched_read_errors: AtomicU64::new(0), + queued_bytes: AtomicU64::new(0), + } + } +} + +/// Mirrors the default retryable-code classification used by +/// `nativelink_util::retry::Retrier::should_retry`: only codes that are +/// always terminal are considered non-retryable. +const fn is_retryable_code(code: Code) -> bool { + !matches!( + code, + Code::Ok + | Code::InvalidArgument + | Code::FailedPrecondition + | Code::OutOfRange + | Code::Unimplemented + | Code::NotFound + | Code::AlreadyExists + | Code::PermissionDenied + | Code::Unauthenticated + ) +} + // This store is usually a pass-through store, but can also be used as a CAS store. Using it as an // AC store has one major side-effect... The has() function may not give the proper size of the // underlying data. This might cause issues if embedded in certain stores. +/// Starting capacity for the stitched-together batch response. Only a hint: +/// most batches are one chunk, and the vec grows if not. +const MAX_BATCH_UPDATE_ENTRIES_HINT: usize = 256; + +/// Groups blobs so no single `BatchUpdateBlobs` RPC carries more than +/// `MAX_WRITE_REQUEST_DATA_BYTES` of payload. +/// +/// An entry larger than the cap on its own still goes out alone. Nothing can +/// be done for it here, since a batch entry cannot be split across messages, +/// and REAPI already tells clients to use `ByteStream` for blobs that size. +fn split_batch_update_requests( + requests: Vec, +) -> Vec> { + let mut chunks = Vec::new(); + let mut current: Vec = Vec::new(); + let mut current_bytes = 0usize; + + for request in requests { + let len = request.data.len(); + if !current.is_empty() && current_bytes.saturating_add(len) > MAX_WRITE_REQUEST_DATA_BYTES { + chunks.push(core::mem::take(&mut current)); + current_bytes = 0; + } + current_bytes = current_bytes.saturating_add(len); + current.push(request); + } + // An empty batch still needs one RPC: the caller expects the upstream's + // answer to an empty request, not a synthesised one. + if !current.is_empty() || chunks.is_empty() { + chunks.push(current); + } + chunks +} + #[derive(Debug, MetricsComponent)] pub struct GrpcStore { #[metric(help = "Instance name for the store")] @@ -119,6 +259,14 @@ pub struct GrpcStore { use_legacy_resource_names: bool, headers: Vec<(MetadataKey, MetadataValue)>, forward_headers: Vec, + /// When configured, coalesces small-blob reads into `BatchReadBlobs` + /// RPCs. `None` means reads always use the `ByteStream` `Read` path. + #[metric(group = "read_batcher")] + read_batcher: Option, + remote_cache_compression_enabled: bool, + /// Used by the read coalescer to hand a strong reference of this store + /// to detached dispatcher tasks. + weak_self: Weak, } impl GrpcStore { @@ -145,6 +293,24 @@ impl GrpcStore { let rpc_timeout = Duration::from_secs(spec.rpc_timeout_s); + let read_batcher = match &spec.experimental_read_batching { + Some(config) => { + error_if!( + config.dispatch_slots == 0, + "experimental_read_batching.dispatch_slots must be greater than zero" + ); + // Batched reads share one upstream RPC across many client + // requests, so per-client forwarded headers (e.g. credentials) + // cannot be attached correctly. + error_if!( + !spec.forward_headers.is_empty(), + "experimental_read_batching is incompatible with forward_headers" + ); + Some(ReadBatcher::new(config)) + } + None => None, + }; + let mut headers = Vec::with_capacity(spec.headers.len()); for (name, value) in &spec.headers { // We lowercase keys as HTTP headers are case-insensitive so we should match all cases @@ -160,7 +326,8 @@ impl GrpcStore { headers.push((key, val)); } - Ok(Arc::new(Self { + Ok(Arc::new_cyclic(|weak_self| Self { + weak_self: weak_self.clone(), instance_name: spec.instance_name.clone(), store_type: spec.store_type, retrier: Retrier::new( @@ -177,6 +344,8 @@ impl GrpcStore { ), rpc_timeout, use_legacy_resource_names: spec.use_legacy_resource_names, + read_batcher, + remote_cache_compression_enabled: spec.remote_cache_compression_enabled(), headers, // We lowercase keys as HTTP headers are case-insensitive so we should match all cases forward_headers: spec @@ -259,22 +428,40 @@ impl GrpcStore { let mut request = grpc_request.into_inner(); request.instance_name.clone_from(&self.instance_name); - self.perform_request(request, |request| async move { - let channel = self - .connection_manager - .connection("batch_update_blobs".into()) - .await - .err_tip(|| "in batch_update_blobs")?; - ContentAddressableStorageClient::new(channel) - .batch_update_blobs(enrich_request( - Request::new(request), - &self.headers, - &self.forward_headers, - )) - .await - .err_tip(|| "in GrpcStore::batch_update_blobs") - }) - .await + + // A batch is one message, so an oversized one cannot be chunked the + // way a ByteStream write can; it has to become several RPCs. Split on + // the accumulated payload and stitch the responses back together in + // request order, which is what the caller matches results by. + let mut responses = + Vec::with_capacity(request.requests.len().min(MAX_BATCH_UPDATE_ENTRIES_HINT)); + for chunk in split_batch_update_requests(core::mem::take(&mut request.requests)) { + let chunk_request = BatchUpdateBlobsRequest { + instance_name: request.instance_name.clone(), + requests: chunk, + digest_function: request.digest_function, + }; + let response = self + .perform_request(chunk_request, |chunk_request| async move { + let channel = self + .connection_manager + .connection("batch_update_blobs".into()) + .await + .err_tip(|| "in batch_update_blobs")?; + ContentAddressableStorageClient::new(channel) + .batch_update_blobs(enrich_request( + Request::new(chunk_request), + &self.headers, + &self.forward_headers, + )) + .await + .err_tip(|| "in GrpcStore::batch_update_blobs") + }) + .await?; + responses.extend(response.into_inner().responses); + } + + Ok(Response::new(BatchUpdateBlobsResponse { responses })) } pub async fn batch_read_blobs( @@ -306,6 +493,217 @@ impl GrpcStore { .await } + /// Enqueues a small-blob read for coalescing into a `BatchReadBlobs` RPC + /// and waits for its result. Returns `None` when the queue is over its + /// byte budget, in which case the caller must fall back to the + /// `ByteStream` `Read` path. + async fn batched_read( + &self, + batcher: &ReadBatcher, + digest: DigestInfo, + ) -> Option> { + // Capture the digest function from the caller's ambient context now; + // the dispatcher runs on a detached task with no such context. + let digest_function: i32 = Context::current() + .get::() + .map_or_else(default_digest_hasher_func, |v| *v) + .proto_digest_func() + .into(); + let (tx, rx) = oneshot::channel(); + { + let mut queue = batcher.queue.lock(); + // Admission control. On overflow gracefully degrade to the + // stream path instead of blocking. + let new_bytes = queue.bytes.saturating_add(digest.size_bytes()); + if new_bytes > batcher.max_queued_bytes { + batcher.queue_bypasses.fetch_add(1, Ordering::Relaxed); + return None; + } + queue.bytes = new_bytes; + batcher.queued_bytes.store(new_bytes, Ordering::Relaxed); + queue.items.push_back(PendingRead { + digest, + digest_function, + tx, + }); + } + + self.maybe_dispatch_read_batches(batcher); + + Some(rx.await.unwrap_or_else(|_| { + Err(make_err!( + Code::Internal, + "Read batch dispatcher dropped result in GrpcStore::batched_read" + )) + })) + } + + /// Tries to start a read batch dispatcher. This is work-conserving: if a + /// dispatch slot is free a dispatcher is started immediately, otherwise + /// one of the active dispatchers is responsible for every currently + /// queued item. The dispatcher runs as a detached task so that + /// cancellation of any individual reader can neither abort an in-flight + /// `BatchReadBlobs` RPC nor strand still-queued waiters. + fn maybe_dispatch_read_batches(&self, batcher: &ReadBatcher) { + let Ok(mut permit) = batcher.dispatch_slots.clone().try_acquire_owned() else { + return; + }; + let Some(store) = self.weak_self.upgrade() else { + return; + }; + background_spawn!("grpc_store_read_batch_dispatch", async move { + let Some(batcher) = &store.read_batcher else { + return; + }; + loop { + store.dispatch_read_batches(batcher).await; + drop(permit); + // Items may have been enqueued between the last drain and + // the permit release. Re-check so they are not stranded + // with no active dispatcher. + if batcher.queue.lock().items.is_empty() { + return; + } + match batcher.dispatch_slots.clone().try_acquire_owned() { + Ok(new_permit) => permit = new_permit, + // Another dispatcher is active and will observe these + // items (or re-check after releasing its own permit). + Err(_) => return, + } + } + }); + } + + /// Drains the pending read queue, sending one `BatchReadBlobs` RPC per + /// drained batch, until the queue is empty. + async fn dispatch_read_batches(&self, batcher: &ReadBatcher) { + loop { + let batch = { + let mut queue = batcher.queue.lock(); + let Some(head) = queue.items.front() else { + return; + }; + // All digests in one BatchReadBlobsRequest must use the same + // digest function. Partition-drain: take items matching the + // head's digest function from anywhere in the queue (up to + // the batch budget) and keep the rest in relative order. + let digest_function = head.digest_function; + let mut batch = Vec::new(); + let mut batch_bytes = 0u64; + let mut rest = VecDeque::with_capacity(queue.items.len()); + while let Some(item) = queue.items.pop_front() { + let item_cost = item + .digest + .size_bytes() + .saturating_add(BATCH_READ_PER_ENTRY_OVERHEAD_BYTES); + if item.digest_function == digest_function + && (batch.is_empty() + || batch_bytes.saturating_add(item_cost) <= batcher.max_batch_bytes) + { + batch_bytes = batch_bytes.saturating_add(item_cost); + queue.bytes = queue.bytes.saturating_sub(item.digest.size_bytes()); + batch.push(item); + } else { + rest.push_back(item); + } + } + queue.items = rest; + batcher.queued_bytes.store(queue.bytes, Ordering::Relaxed); + batch + }; + self.send_read_batch(batcher, batch).await; + } + } + + /// Sends one `BatchReadBlobs` RPC for `batch` and demultiplexes the + /// per-blob responses back to the waiting readers. One failed item does + /// not affect its batch-mates; failure of the whole RPC is broadcast to + /// every item in the batch. + async fn send_read_batch(&self, batcher: &ReadBatcher, batch: Vec) { + let Some(digest_function) = batch.first().map(|item| item.digest_function) else { + return; + }; + // Servers may dedupe duplicate digests within one request, so group + // the waiters per digest and request each digest exactly once, + // fanning the (refcounted) data out to every waiter. + let batch_len = u64::try_from(batch.len()).unwrap_or(u64::MAX); + let mut waiters: HashMap> = HashMap::new(); + for item in batch { + waiters.entry(item.digest).or_default().push(item); + } + let request = BatchReadBlobsRequest { + // batch_read_blobs() overwrites the instance name, so there is + // no need to set it here. + instance_name: String::new(), + digests: waiters.keys().map(|digest| (*digest).into()).collect(), + acceptable_compressors: vec![], + digest_function, + }; + batcher.batches_sent.fetch_add(1, Ordering::Relaxed); + batcher + .blobs_batched + .fetch_add(batch_len, Ordering::Relaxed); + let response = match self.batch_read_blobs(Request::new(request)).await { + Ok(response) => response.into_inner(), + Err(err) => { + // The whole RPC failed, so every waiter in this batch gets + // the error. Waiters may have gone away, ignore send errors. + for item in waiters.into_values().flatten() { + drop(item.tx.send(Err(err.clone()))); + } + return; + } + }; + for entry in response.responses { + let Some(Ok(entry_digest)) = entry.digest.map(DigestInfo::try_from) else { + continue; + }; + let Some(items) = waiters.remove(&entry_digest) else { + continue; + }; + let entry_len = u64::try_from(entry.data.len()).unwrap_or(u64::MAX); + let result = if let Some(status) = entry.status.filter(|status| status.code != 0) { + Err(Error::from(status) + .append("Batch read entry failed in GrpcStore::send_read_batch")) + } else if entry.compressor != 0 { + // We requested no acceptable compressors, so data must be + // returned with the identity compressor. + Err(make_err!( + Code::Internal, + "BatchReadBlobs entry for {entry_digest} used unsupported compressor {}", + entry.compressor + )) + } else if entry_len != entry_digest.size_bytes() { + Err(make_err!( + Code::Internal, + "BatchReadBlobs entry for {entry_digest} returned {entry_len} bytes, expected {}", + entry_digest.size_bytes() + )) + } else { + Ok(entry.data) + }; + if result.is_err() { + batcher.batched_read_errors.fetch_add( + u64::try_from(items.len()).unwrap_or(u64::MAX), + Ordering::Relaxed, + ); + } + for item in items { + drop(item.tx.send(result.clone())); + } + } + // Any waiter with no matching response entry is missing upstream. + for item in waiters.into_values().flatten() { + batcher.batched_read_errors.fetch_add(1, Ordering::Relaxed); + let err = make_err!( + Code::NotFound, + "Blob {} not found in BatchReadBlobs response", + item.digest + ); + drop(item.tx.send(Err(err))); + } + } + pub async fn get_tree( &self, grpc_request: Request, @@ -335,6 +733,64 @@ impl GrpcStore { .await } + pub async fn split_blob( + &self, + grpc_request: Request, + ) -> Result, Error> { + error_if!( + matches!(self.store_type, nativelink_config::stores::StoreType::Ac), + "CAS operation on AC store" + ); + + let mut request = grpc_request.into_inner(); + request.instance_name.clone_from(&self.instance_name); + self.perform_request(request, |request| async move { + let channel = self + .connection_manager + .connection(format!("split_blob: {:?}", request.blob_digest)) + .await + .err_tip(|| "in split_blob")?; + ContentAddressableStorageClient::new(channel) + .split_blob(enrich_request( + Request::new(request), + &self.headers, + &self.forward_headers, + )) + .await + .err_tip(|| "in GrpcStore::split_blob") + }) + .await + } + + pub async fn splice_blob( + &self, + grpc_request: Request, + ) -> Result, Error> { + error_if!( + matches!(self.store_type, nativelink_config::stores::StoreType::Ac), + "CAS operation on AC store" + ); + + let mut request = grpc_request.into_inner(); + request.instance_name.clone_from(&self.instance_name); + self.perform_request(request, |request| async move { + let channel = self + .connection_manager + .connection(format!("splice_blob: {:?}", request.blob_digest)) + .await + .err_tip(|| "in splice_blob")?; + ContentAddressableStorageClient::new(channel) + .splice_blob(enrich_request( + Request::new(request), + &self.headers, + &self.forward_headers, + )) + .await + .err_tip(|| "in GrpcStore::splice_blob") + }) + .await + } + fn get_read_request(&self, mut request: ReadRequest) -> Result { const IS_UPLOAD_FALSE: bool = false; let mut resource_info = ResourceInfo::new(&request.resource_name, IS_UPLOAD_FALSE)?; @@ -393,6 +849,19 @@ impl GrpcStore { &self, stream: WriteRequestStreamWrapper, ) -> Result, Error> + where + T: Stream> + Unpin + Send + 'static, + E: Into + 'static, + { + const RESUMABLE: bool = true; + self.write_internal(stream, RESUMABLE).await + } + + async fn write_internal( + &self, + stream: WriteRequestStreamWrapper, + resumable: bool, + ) -> Result, Error> where T: Stream> + Unpin + Send + 'static, E: Into + 'static, @@ -402,10 +871,11 @@ impl GrpcStore { "CAS operation on AC store" ); - let local_state = Arc::new(Mutex::new(WriteState::new( - self.instance_name.clone(), - stream, - ))); + let mut write_state = WriteState::new(self.instance_name.clone(), stream); + if !resumable { + write_state.set_non_resumable(); + } + let local_state = Arc::new(Mutex::new(write_state)); let write_start = std::time::Instant::now(); let instance_name = self.instance_name.clone(); @@ -699,6 +1169,387 @@ impl GrpcStore { .await .map(|_| len) } + + /// Uploads `digest` as a REAPI `compressed-blobs/zstd` write: the raw + /// bytes from `reader` are zstd-encoded on the fly and streamed with + /// compressed write offsets. Used when + /// `experimental_remote_cache_compression` is enabled and the blob meets + /// the size threshold. + async fn update_compressed( + self: Pin<&Self>, + digest: DigestInfo, + reader: DropCloserReadHalf, + ) -> Result { + enum UploadCompletion { + Write(Result<(), Error>), + Encode(Result<(), Error>, Result<(), Error>), + } + + // Compressed writes are NON-resumable: the server-side protocol + // rejects replays from a nonzero compressed offset, so a mid-stream + // failure must surface immediately instead of burning the retry + // budget on guaranteed-rejected resumes. + const NON_RESUMABLE: bool = false; + + struct LocalState { + resource_name: String, + compressed_rx: DropCloserReadHalf, + did_error: bool, + bytes_received: i64, + } + + let mut buf = Uuid::encode_buffer(); + let uuid = Uuid::new_v4().hyphenated().encode_lower(&mut buf); + let resource_name = if self.use_legacy_resource_names { + format!( + "{}/uploads/{}/compressed-blobs/zstd/{}/{}", + &self.instance_name, + uuid, + digest.packed_hash(), + digest.size_bytes(), + ) + } else { + let digest_function = Context::current() + .get::() + .map_or_else(default_digest_hasher_func, |v| *v) + .proto_digest_func() + .as_str_name() + .to_ascii_lowercase(); + format!( + "{}/uploads/{}/compressed-blobs/zstd/{}/{}/{}", + &self.instance_name, + uuid, + digest_function, + digest.packed_hash(), + digest.size_bytes(), + ) + }; + + let (compressed_tx, compressed_rx) = make_buf_channel_pair(); + let mut reader = reader; + let encode_fut = stream_encode_compressed_download_from_reader( + &mut reader, + compressor::Value::Zstd, + WIRE_COMPRESSION_ZSTD_LEVEL, + compressed_tx, + ); + + let local_state = LocalState { + resource_name, + compressed_rx, + did_error: false, + bytes_received: 0, + }; + let stream = Box::pin(unfold(local_state, |mut local_state| async move { + if local_state.did_error { + error!("GrpcStore::update_compressed() polled stream after error was returned"); + return None; + } + let data = match local_state + .compressed_rx + .recv() + .await + .err_tip(|| "In GrpcStore::update_compressed()") + { + Ok(data) => data, + Err(err) => { + local_state.did_error = true; + return Some((Err(err), local_state)); + } + }; + let write_offset = local_state.bytes_received; + local_state.bytes_received += data.len().try_into().unwrap_or(i64::MAX); + Some(( + Ok(WriteRequest { + resource_name: local_state.resource_name.clone(), + write_offset, + finish_write: data.is_empty(), // EOF is when no data was polled. + data, + }), + local_state, + )) + })); + + // The encoder must be driven concurrently with the RPC: the request + // stream's first message is the encoder's first output chunk. + let write_fut = async { + self.write_internal( + WriteRequestStreamWrapper::from(stream) + .await + .err_tip(|| "in GrpcStore::update_compressed()")?, + NON_RESUMABLE, + ) + .await + .map(|_| ()) + .err_tip(|| "in GrpcStore::update_compressed()") + }; + let completion = async { + let write_fut = Box::pin(write_fut); + let encode_fut = Box::pin(encode_fut); + match future::select(write_fut, encode_fut).await { + future::Either::Left((write_result, encode_fut)) => { + drop(encode_fut); + UploadCompletion::Write(write_result) + } + future::Either::Right((encode_result, write_fut)) => { + UploadCompletion::Encode(encode_result, write_fut.await) + } + } + } + .await; + match completion { + UploadCompletion::Write(write_result) => { + write_result?; + // The server settled the write before consuming the whole + // stream (REAPI early completion of a duplicate upload). Do + // not await the encoder: it may be blocked on a stalled + // producer. Cancel it, then drain the raw reader in the + // background so the producer can finish without observing a + // broken pipe from a successful upload. + background_spawn!("grpc_store_compressed_upload_drain", async move { + if let Err(err) = reader.drain().await { + debug!( + ?err, + "Compressed upload reader drain failed after early completion" + ); + } + }); + } + UploadCompletion::Encode(encode_result, write_result) => { + write_result?; + // An encode error with a successful write means the server + // finished without consuming the whole stream; the upload + // itself succeeded. + if let Err(err) = encode_result { + debug!( + ?err, + "Compressed upload encoder ended early after successful write" + ); + // The encoder stopped early, most likely because the + // server completed the write while its response stream + // was still being finalized. It has already released its + // borrow of `reader`, so drain any raw input the producer + // still has in flight. On a clean encode the reader is + // already at EOF and draining would be a no-op, so the + // happy path spawns nothing. + background_spawn!("grpc_store_compressed_upload_drain", async move { + if let Err(err) = reader.drain().await { + debug!( + ?err, + "Compressed upload reader drain failed after early completion" + ); + } + }); + } + } + } + Ok(digest.size_bytes()) + } + + /// Reads all of `digest` as a REAPI `compressed-blobs/zstd` read, + /// streaming decode into `writer` with size and digest verification at + /// EOF. Returns `Ok(None)` on success. On a retryable transport failure + /// before any decoded bytes were forwarded, it returns `Ok(Some(0))` so + /// the caller can restart through the identity path. Failures after any + /// output, and other terminal errors (including decode/digest mismatches), + /// propagate as `Err`. + async fn get_part_compressed( + self: Pin<&Self>, + digest: DigestInfo, + writer: &mut DropCloserWriteHalf, + ) -> Result, Error> { + #[derive(Debug)] + enum CompressedReadStage { + Feed, + Decode, + Pump, + } + + let resource_name = if self.use_legacy_resource_names { + format!( + "{}/compressed-blobs/zstd/{}/{}", + &self.instance_name, + digest.packed_hash(), + digest.size_bytes(), + ) + } else { + let digest_function = Context::current() + .get::() + .map_or_else(default_digest_hasher_func, |v| *v) + .proto_digest_func() + .as_str_name() + .to_ascii_lowercase(); + format!( + "{}/compressed-blobs/zstd/{}/{}/{}", + &self.instance_name, + digest_function, + digest.packed_hash(), + digest.size_bytes(), + ) + }; + + let mut stream = match self + .read_internal(ReadRequest { + resource_name, + read_offset: 0, + read_limit: 0, + }) + .await + { + Ok(stream) => stream, + Err(err) if is_retryable_code(err.code) => { + warn!( + ?err, + "Compressed read failed to start, falling back to identity read" + ); + return Ok(Some(0)); + } + Err(err) => return Err(err.append("in GrpcStore::get_part_compressed()")), + }; + + let digest_function = Context::current() + .get::() + .map_or_else(default_digest_hasher_func, |v| *v); + let (mut compressed_tx, compressed_rx) = make_buf_channel_pair(); + let (decoded_tx, mut decoded_rx) = make_buf_channel_pair(); + let decode_fut = stream_decode_compressed_upload( + compressed_rx, + compressor::Value::Zstd, + digest, + digest_function, + decoded_tx, + ); + let feed_fut = async { + loop { + match stream.next().await { + None => { + // A send_eof failure means the decoder already + // settled and dropped its receiver; its result is + // authoritative, so this is not a feed error. + drop(compressed_tx.send_eof()); + return Ok(()); + } + Some(Ok(message)) => { + // Empty chunks are legal on the wire but are the EOF + // marker in buf_channel; skip them. + if !message.data.is_empty() + && compressed_tx.send(message.data).await.is_err() + { + // The decoder stopped consuming (it settled or + // aborted on bad data). Its result decides the + // outcome; reporting a feed error here would + // misclassify a decoder-detected data error as + // retryable transport fallout. + return Ok(()); + } + } + Some(Err(status)) => return Err(Into::::into(status)), + } + } + }; + let forwarded = AtomicU64::new(0); + // Set once the decoder's EOF has been forwarded. The decoder only + // sends EOF after the whole blob passed its size and digest checks + // (and `buf_channel` reports a sender dropped without EOF as an error + // rather than as EOF), so this is a positive signal that the download + // completed and was verified. + let download_complete = AtomicBool::new(false); + let pump_fut = async { + loop { + let chunk = decoded_rx + .recv() + .await + .err_tip(|| "in GrpcStore::get_part_compressed()")?; + if chunk.is_empty() { + writer + .send_eof() + .err_tip(|| "in GrpcStore::get_part_compressed()")?; + download_complete.store(true, Ordering::Relaxed); + return Ok(()); + } + let chunk_len = chunk.len() as u64; + writer + .send(chunk) + .await + .err_tip(|| "in GrpcStore::get_part_compressed()")?; + // Only bytes accepted by the downstream writer are eligible + // to influence retry policy. + forwarded.fetch_add(chunk_len, Ordering::Relaxed); + } + }; + + let result = tokio::try_join!( + async { + feed_fut + .await + .map_err(|err| (CompressedReadStage::Feed, err)) + }, + async { + decode_fut + .await + .map_err(|err| (CompressedReadStage::Decode, err)) + }, + async { + pump_fut + .await + .map_err(|err| (CompressedReadStage::Pump, err)) + }, + ); + + match result { + Ok(((), (), ())) => Ok(None), + // The blob was fully delivered and verified before this error + // happened (for example a transport failure while the response + // trailer was being finalized). Falling back would re-read a + // range that has already been written, into a closed writer. + Err((stage, err)) if download_complete.load(Ordering::Relaxed) => { + debug!( + ?stage, + ?err, + "Compressed read completed and verified before a late stage error" + ); + Ok(None) + } + Err((CompressedReadStage::Decode, err)) if err.code == Code::InvalidArgument => { + Err(err.append("in GrpcStore::get_part_compressed()")) + } + // Pump failures are local delivery failures: either the + // downstream consumer went away or the decoded channel closed + // without EOF. An identity re-read helps in neither case, so + // never fall back — `buf_channel` reports a broken receiver as + // `Internal`, which `is_retryable_code` would otherwise classify + // as retryable. + Err((CompressedReadStage::Pump, err)) => { + Err(err.append("in GrpcStore::get_part_compressed()")) + } + Err((CompressedReadStage::Feed, err)) if !is_retryable_code(err.code) => { + Err(err.append("in GrpcStore::get_part_compressed()")) + } + // A clean identity restart is only safe before unverified decoded + // bytes have been exposed to the downstream consumer. + Err((stage, err)) if forwarded.load(Ordering::Relaxed) == 0 => { + warn!( + ?stage, + ?err, + "Compressed read interrupted before forwarding data, falling back to \ + identity read" + ); + Ok(Some(0)) + } + Err((stage, err)) => { + debug!( + ?stage, + ?err, + forwarded = forwarded.load(Ordering::Relaxed), + "Compressed read interrupted after forwarding unverified data" + ); + Err(err.append( + "in GrpcStore::get_part_compressed(): refusing identity fallback after \ + forwarding unverified decoded data", + )) + } + } + } } #[async_trait] @@ -785,13 +1636,26 @@ impl StoreDriver for GrpcStore { reader: DropCloserReadHalf, did_error: bool, bytes_received: i64, + /// Remainder of a buffer too large to send as one `WriteRequest`. + pending: Bytes, } + let is_digest_key = matches!(key, StoreKey::Digest(_)); let digest = key.into_digest(); if matches!(self.store_type, nativelink_config::stores::StoreType::Ac) { return self.update_action_result_from_bytes(digest, reader).await; } + // Only real digest keys may take the compressed path: for a string key + // `into_digest()` hashes the key itself, so the remote's mandatory + // uncompressed-digest verification would reject the upload. + if self.remote_cache_compression_enabled + && is_digest_key + && digest.size_bytes() >= WIRE_COMPRESSION_MIN_SIZE_BYTES + { + return self.update_compressed(digest, reader).await; + } + let mut buf = Uuid::encode_buffer(); let resource_name = if self.use_legacy_resource_names { format!( @@ -828,6 +1692,7 @@ impl StoreDriver for GrpcStore { reader, did_error: false, bytes_received: 0, + pending: Bytes::new(), }; let stream = Box::pin(unfold(local_state, |mut local_state| async move { @@ -835,27 +1700,45 @@ impl StoreDriver for GrpcStore { error!("GrpcStore::update() polled stream after error was returned"); return None; } - let data = match local_state - .reader - .recv() - .await - .err_tip(|| "In GrpcStore::update()") - { - Ok(data) => data, - Err(err) => { - local_state.did_error = true; - return Some((Err(err), local_state)); + // Drain any remainder before reading more. + let data = if local_state.pending.is_empty() { + match local_state + .reader + .recv() + .await + .err_tip(|| "In GrpcStore::update()") + { + Ok(data) => data, + Err(err) => { + local_state.did_error = true; + return Some((Err(err), local_state)); + } } + } else { + core::mem::take(&mut local_state.pending) + }; + + // `update_oneshot` writes a whole blob in one go, and a message + // over the receiver's decode limit is rejected outright rather + // than degrading, so split rather than forwarding it as-is. + let data = if data.len() > MAX_WRITE_REQUEST_DATA_BYTES { + let rest = data.slice(MAX_WRITE_REQUEST_DATA_BYTES..); + local_state.pending = rest; + data.slice(..MAX_WRITE_REQUEST_DATA_BYTES) + } else { + data }; let write_offset = local_state.bytes_received; - local_state.bytes_received += data.len() as i64; + local_state.bytes_received += data.len().try_into().unwrap_or(i64::MAX); Some(( Ok(WriteRequest { resource_name: local_state.resource_name.clone(), write_offset, - finish_write: data.is_empty(), // EOF is when no data was polled. + // EOF is when no data was polled. A split always leaves a + // non-empty remainder, so this cannot fire early. + finish_write: data.is_empty(), data, }), local_state, @@ -887,6 +1770,7 @@ impl StoreDriver for GrpcStore { read_limit: i64, } + let is_digest_key = matches!(key, StoreKey::Digest(_)); let digest = key.into_digest(); if matches!(self.store_type, nativelink_config::stores::StoreType::Ac) { let offset = usize::try_from(offset).err_tip(|| "Could not convert offset to usize")?; @@ -904,6 +1788,66 @@ impl StoreDriver for GrpcStore { return writer.send_eof(); } + // When configured, coalesce full reads of small blobs into + // BatchReadBlobs RPCs. `batched_read` returns `None` when the queue + // is over budget, in which case we fall through to the stream path. + if let Some(batcher) = &self.read_batcher + && is_digest_key + && offset == 0 + && length.is_none_or(|len| len >= digest.size_bytes()) + && digest.size_bytes() <= batcher.max_blob_size_bytes + && let Some(result) = self.batched_read(batcher, digest).await + { + match result { + Ok(data) => { + if !data.is_empty() { + writer + .send(data) + .await + .err_tip(|| "Failed to write data in GrpcStore::get_part()")?; + } + return writer + .send_eof() + .err_tip(|| "Failed to send EOF in GrpcStore::get_part()"); + } + // A retryable error falls through to the ByteStream path + // below, which re-enters the full retry machinery. This + // matches the retry behavior reads had before batching. + Err(err) if is_retryable_code(err.code) => { + warn!( + ?err, + "Batched read failed with retryable error, falling back to ByteStream read", + ); + } + Err(err) => return Err(err.append("in GrpcStore::get_part()")), + } + } + + let mut length = length; + if self.remote_cache_compression_enabled + && is_digest_key + && offset == 0 + && length.is_none_or(|len| len >= digest.size_bytes()) + && digest.size_bytes() >= WIRE_COMPRESSION_MIN_SIZE_BYTES + { + match self.get_part_compressed(digest, writer).await? { + None => return Ok(()), + // Retryable failures before any compressed output restart + // through identity. Partial compressed reads are terminal and + // must never reach this branch with a nonzero offset. + Some(0) => { + length = Some(digest.size_bytes()); + } + Some(forwarded) => { + return Err(make_err!( + Code::Internal, + "Compressed identity fallback returned unsafe nonzero offset {}", + forwarded + )); + } + } + } + let resource_name = if self.use_legacy_resource_names { format!( "{}/blobs/{}/{}", @@ -954,7 +1898,7 @@ impl StoreDriver for GrpcStore { loop { let data = match stream.next().await { // Create an empty response to represent EOF. - None => bytes::Bytes::new(), + None => Bytes::new(), Some(Ok(message)) => message.data, Some(Err(status)) => { return Some(( @@ -966,7 +1910,8 @@ impl StoreDriver for GrpcStore { )); } }; - let length = data.len() as i64; + let length = data.len().try_into().unwrap_or(i64::MAX); + // This is the usual exit from the loop at EOF. if length == 0 { let eof_result = local_state @@ -1003,10 +1948,7 @@ impl StoreDriver for GrpcStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { Err(Error::new( Code::Internal, "gRPC stores are incompatible with removal callbacks".to_string(), diff --git a/nativelink-store/src/lib.rs b/nativelink-store/src/lib.rs index 5fc13fccd..1ceea189a 100644 --- a/nativelink-store/src/lib.rs +++ b/nativelink-store/src/lib.rs @@ -31,6 +31,7 @@ pub mod grpc_store; pub mod memory_store; pub mod mongo_store; pub mod noop_store; +pub mod oci_store; pub mod ontap_s3_existence_cache_store; pub mod ontap_s3_store; pub mod r2_store; diff --git a/nativelink-store/src/memory_store.rs b/nativelink-store/src/memory_store.rs index ef7fa6b57..2a71227bc 100644 --- a/nativelink-store/src/memory_store.rs +++ b/nativelink-store/src/memory_store.rs @@ -31,11 +31,11 @@ use nativelink_util::health_utils::{ HealthRegistryBuilder, HealthStatusIndicator, default_health_status_indicator, }; use nativelink_util::store_trait::{ - RemoveItemCallback, StoreDriver, StoreKey, StoreKeyBorrow, StoreOptimizations, UploadSizeInfo, + RemoveCallback, StoreDriver, StoreKey, StoreKeyBorrow, StoreOptimizations, UploadSizeInfo, }; use tracing::warn; -use crate::callback_utils::RemoveItemCallbackHolder; +use crate::callback_utils::RemoveCallbackHolder; use crate::cas_utils::is_zero_digest; #[derive(Clone)] @@ -67,7 +67,7 @@ pub struct MemoryStore { StoreKey<'static>, BytesWrapper, SystemTime, - RemoveItemCallbackHolder, + RemoveCallbackHolder, >, /// The eviction policy's `max_bytes` (0 = unbounded). Cached here so `update` /// can skip writes larger than the entire store budget without buffering @@ -287,12 +287,9 @@ impl StoreDriver for MemoryStore { registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.evicting_map - .add_remove_callback(RemoveItemCallbackHolder::new(callback)); + .add_remove_callback(RemoveCallbackHolder::new(callback)); Ok(()) } } diff --git a/nativelink-store/src/mongo_store.rs b/nativelink-store/src/mongo_store.rs index 3f784c7fd..5492055d3 100644 --- a/nativelink-store/src/mongo_store.rs +++ b/nativelink-store/src/mongo_store.rs @@ -33,7 +33,7 @@ use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatus, HealthStatusIndicator}; use nativelink_util::spawn; use nativelink_util::store_trait::{ - BoolValue, RemoveItemCallback, SchedulerCurrentVersionProvider, SchedulerIndexProvider, + BoolValue, RemoveCallback, SchedulerCurrentVersionProvider, SchedulerIndexProvider, SchedulerStore, SchedulerStoreDataProvider, SchedulerStoreDecodeTo, SchedulerStoreKeyProvider, SchedulerSubscription, SchedulerSubscriptionManager, StoreDriver, StoreKey, UploadSizeInfo, }; @@ -493,7 +493,7 @@ impl StoreDriver for ExperimentalMongoStore { data.extend_from_slice(&chunk); } - let size = data.len() as i64; + let size = data.len().try_into().unwrap_or(i64::MAX); // Create document let doc = doc! { @@ -627,10 +627,7 @@ impl StoreDriver for ExperimentalMongoStore { registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { // drop because we don't remove anything from Mongo Ok(()) } diff --git a/nativelink-store/src/noop_store.rs b/nativelink-store/src/noop_store.rs index b7aaa7a8d..98b96a505 100644 --- a/nativelink-store/src/noop_store.rs +++ b/nativelink-store/src/noop_store.rs @@ -23,7 +23,7 @@ use nativelink_metric::{ use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, + RemoveCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, }; #[derive(Debug, Default, Clone, Copy)] @@ -101,10 +101,7 @@ impl StoreDriver for NoopStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { // does nothing, so drop Ok(()) } diff --git a/nativelink-store/src/oci_store.rs b/nativelink-store/src/oci_store.rs new file mode 100644 index 000000000..3517690ba --- /dev/null +++ b/nativelink-store/src/oci_store.rs @@ -0,0 +1,144 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::time::Duration; +use std::borrow::Cow; +use std::sync::Arc; + +use aws_config::default_provider::credentials::DefaultCredentialsChain; +use aws_config::provider_config::ProviderConfig; +use aws_config::{AppName, BehaviorVersion}; +use aws_sdk_s3::Client; +use aws_sdk_s3::config::{ + Credentials, Region, RequestChecksumCalculation, ResponseChecksumValidation, +}; +use aws_smithy_runtime_api::client::http::HttpClient as SmithyHttpClient; +use nativelink_config::stores::{ExperimentalAwsSpec, ExperimentalOciSpec}; +use nativelink_error::Error; +use nativelink_util::instant_wrapper::InstantWrapper; + +use crate::common_s3_utils::TlsClient; +use crate::s3_store::S3Store; + +/// OCI-shaped config adapter over [`S3Store`]. Builds an S3 SDK client pointed +/// at Oracle Cloud Infrastructure Object Storage via its Amazon S3 +/// Compatibility API and hands it to `S3Store::new_with_client_and_jitter`. +/// +/// The compatibility API requires path-style addressing: the namespace lives in +/// the host and the bucket is the first path segment +/// (`https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com/{bucket}/{object}`), +/// so `force_path_style(true)` is set on the client. Requests are signed with +/// AWS `SigV4` using the OCI region as the signing region; credentials come from +/// a Customer Secret Key when supplied, otherwise the default AWS credential +/// chain. +#[derive(Debug, Clone, Copy)] +pub struct OciStore; + +impl OciStore { + #[allow(clippy::new_ret_no_self)] // Because usually everyone returns themselves + pub async fn new( + spec: &ExperimentalOciSpec, + now_fn: NowFn, + ) -> Result>, Error> + where + I: InstantWrapper, + NowFn: Fn() -> I + Send + Sync + Unpin + 'static, + { + Self::new_with_http_client(spec, TlsClient::new(&spec.common.clone()), now_fn).await + } + + /// Builds the store with a caller-supplied HTTP client. Production uses + /// [`Self::new`] (which injects a [`TlsClient`]); tests inject a mock (e.g. + /// `StaticReplayClient`) to exercise the OCI-specific wire behavior — + /// path-style URLs and the absence of `aws-chunked` — without a live bucket. + #[allow(clippy::new_ret_no_self)] + pub async fn new_with_http_client( + spec: &ExperimentalOciSpec, + http_client: C, + now_fn: NowFn, + ) -> Result>, Error> + where + I: InstantWrapper, + NowFn: Fn() -> I + Send + Sync + Unpin + 'static, + C: SmithyHttpClient + Clone + 'static, + { + let aws_spec = Self::build_aws_spec(spec); + let jitter_fn = spec.common.retry.make_jitter_fn(); + + let endpoint = Self::derive_endpoint(spec); + let region = Region::new(Cow::Owned(spec.region.clone())); + + let mut config_builder = aws_sdk_s3::Config::builder() + .behavior_version(BehaviorVersion::latest()) + .app_name(AppName::new("nativelink").expect("valid app name")) + .timeout_config( + aws_config::timeout::TimeoutConfig::builder() + .connect_timeout(Duration::from_secs(15)) + .build(), + ) + .region(region.clone()) + .endpoint_url(&endpoint) + // OCI's compatibility endpoint embeds the bucket in the path, not as + // a subdomain, so virtual-hosted addressing must be disabled. + .force_path_style(true) + // OCI does not support the AWS SDK's default flexible-checksum + // behavior. + .request_checksum_calculation(RequestChecksumCalculation::WhenRequired) + .response_checksum_validation(ResponseChecksumValidation::WhenRequired) + .http_client(http_client.clone()); + + config_builder = if let Some(key_id) = &spec.access_key_id + && let Some(secret) = &spec.secret_access_key + { + config_builder.credentials_provider(Credentials::new( + key_id, + secret, + None, + None, + "oci-customer-secret-key", + )) + } else { + let default_chain = DefaultCredentialsChain::builder() + .configure( + ProviderConfig::without_region() + .with_region(Some(region)) + .with_http_client(http_client), + ) + .build() + .await; + config_builder.credentials_provider(default_chain) + }; + + let s3_client = Client::from_conf(config_builder.build()); + + S3Store::new_with_client_and_jitter(&aws_spec, s3_client, jitter_fn, now_fn) + } + + /// Derives the OCI Object Storage path-style S3-compatibility endpoint from + /// the namespace and region. + pub fn derive_endpoint(spec: &ExperimentalOciSpec) -> String { + format!( + "https://{}.compat.objectstorage.{}.oci.customer-oci.com", + spec.namespace, spec.region + ) + } + + pub fn build_aws_spec(spec: &ExperimentalOciSpec) -> ExperimentalAwsSpec { + ExperimentalAwsSpec { + region: spec.region.clone(), + bucket: spec.bucket.clone(), + common: spec.common.clone(), + } + } +} diff --git a/nativelink-store/src/ontap_s3_existence_cache_store.rs b/nativelink-store/src/ontap_s3_existence_cache_store.rs index 264e18660..e238fdb9b 100644 --- a/nativelink-store/src/ontap_s3_existence_cache_store.rs +++ b/nativelink-store/src/ontap_s3_existence_cache_store.rs @@ -36,7 +36,7 @@ use nativelink_util::instant_wrapper::InstantWrapper; use nativelink_util::metrics_utils::CounterWithTime; use nativelink_util::spawn; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use serde::{Deserialize, Serialize}; use tokio::fs; @@ -539,10 +539,7 @@ where self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.inner_store.register_remove_callback(callback) } } diff --git a/nativelink-store/src/ontap_s3_store.rs b/nativelink-store/src/ontap_s3_store.rs index 42335d0f3..be7868de6 100644 --- a/nativelink-store/src/ontap_s3_store.rs +++ b/nativelink-store/src/ontap_s3_store.rs @@ -47,7 +47,7 @@ use nativelink_util::buf_channel::{ use nativelink_util::health_utils::{HealthStatus, HealthStatusIndicator}; use nativelink_util::instant_wrapper::InstantWrapper; use nativelink_util::retry::{Retrier, RetryResult}; -use nativelink_util::store_trait::{RemoveItemCallback, StoreDriver, StoreKey, UploadSizeInfo}; +use nativelink_util::store_trait::{RemoveCallback, StoreDriver, StoreKey, UploadSizeInfo}; use parking_lot::Mutex; use rustls::{ClientConfig, RootCertStore}; use rustls_pki_types::CertificateDer; @@ -74,8 +74,6 @@ const DEFAULT_MAX_RETRY_BUFFER_PER_REQUEST: usize = 20 * 1024 * 1024; // 20MB // Default limit for concurrent part uploads per multipart upload const DEFAULT_MULTIPART_MAX_CONCURRENT_UPLOADS: usize = 10; -type RemoveCallback = Arc; - #[derive(Debug, MetricsComponent)] pub struct OntapS3Store { s3_client: Arc, @@ -86,7 +84,7 @@ pub struct OntapS3Store { key_prefix: String, retrier: Retrier, #[metric(help = "The number of seconds to consider an object expired")] - consider_expired_after_s: i64, + consider_expired_after_s: u64, #[metric(help = "The number of bytes to buffer for retrying requests")] max_retry_buffer_per_request: usize, #[metric(help = "The number of concurrent uploads allowed for multipart uploads")] @@ -207,7 +205,7 @@ where jitter_fn, spec.common.retry.clone(), ), - consider_expired_after_s: i64::from(spec.common.consider_expired_after_s), + consider_expired_after_s: u64::from(spec.common.consider_expired_after_s), max_retry_buffer_per_request: spec .common .max_retry_buffer_per_request @@ -243,8 +241,12 @@ where if self.consider_expired_after_s != 0 && let Some(last_modified) = head_object_output.last_modified { - let now_s = (self.now_fn)().unix_timestamp() as i64; - if last_modified.secs() + self.consider_expired_after_s <= now_s { + let now_s = (self.now_fn)().unix_timestamp(); + if TryInto::::try_into(last_modified.secs()) + .unwrap_or(u64::MAX) + + self.consider_expired_after_s + <= now_s + { let remove_callbacks = self.remove_callbacks.lock().clone(); let mut callbacks: FuturesUnordered<_> = remove_callbacks .into_iter() @@ -391,7 +393,7 @@ where .put_object() .bucket(&self.bucket) .key(s3_path.clone()) - .content_length(sz as i64) + .content_length(sz.try_into().unwrap_or(i64::MAX)) .body( ByteStream::from(body_bytes) ) @@ -767,10 +769,7 @@ where self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.remove_callbacks.lock().push(callback); Ok(()) } diff --git a/nativelink-store/src/redis_store.rs b/nativelink-store/src/redis_store.rs index 78e29075c..4c81ac470 100644 --- a/nativelink-store/src/redis_store.rs +++ b/nativelink-store/src/redis_store.rs @@ -35,14 +35,16 @@ use nativelink_error::{Code, Error, ResultExt, make_err, make_input_err}; use nativelink_metric::MetricsComponent; use nativelink_redis_tester::SubscriptionManagerNotify; use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; +use nativelink_util::common::DigestInfo; use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatus, HealthStatusIndicator}; -use nativelink_util::spawn; +use nativelink_util::metrics::{record_connection_acquired, record_connection_reconnect}; use nativelink_util::store_trait::{ - BoolValue, RemoveItemCallback, SchedulerCurrentVersionProvider, SchedulerIndexProvider, + BoolValue, RemoveCallback, SchedulerCurrentVersionProvider, SchedulerIndexProvider, SchedulerStore, SchedulerStoreDataProvider, SchedulerStoreDecodeTo, SchedulerStoreKeyProvider, SchedulerSubscription, SchedulerSubscriptionManager, StoreDriver, StoreKey, UploadSizeInfo, }; use nativelink_util::task::JoinHandleDropGuard; +use nativelink_util::{background_spawn, spawn}; use parking_lot::{Mutex, RwLock}; use patricia_tree::StringPatriciaMap; use redis::aio::{ConnectionLike, ConnectionManager, ConnectionManagerConfig}; @@ -53,9 +55,11 @@ use redis::{ AsyncCommands, AsyncIter, Client, IntoConnectionInfo, PushInfo, ScanOptions, Script, Value, pipe, }; +use serde::Deserialize; +use serde::de::IntoDeserializer; use tokio::select; use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel}; -use tokio::sync::{OwnedSemaphorePermit, Semaphore}; +use tokio::sync::{OnceCell, OwnedSemaphorePermit, Semaphore}; use tokio::time::{sleep, timeout}; use tokio_stream::wrappers::UnboundedReceiverStream; use tracing::{debug, error, info, trace, warn}; @@ -122,6 +126,16 @@ pub const DEFAULT_MAX_COUNT_PER_CURSOR: u64 = 1_500; const DEFAULT_CLIENT_PERMITS: usize = 500; +/// Converts a TTL to the seconds `EXPIRE` takes. +/// +/// Clamped to at least one second. Redis treats `EXPIRE` with a value of zero +/// or less as "delete now", so a sub-second duration reaching here would +/// destroy the value it was meant to protect. Config already rejects zero, so +/// this only guards a future caller. +fn ttl_seconds(key_ttl: Duration) -> i64 { + i64::try_from(key_ttl.as_secs()).unwrap_or(i64::MAX).max(1) +} + /// A wrapper around Redis to allow it to be reconnected. pub trait RedisManager where @@ -301,6 +315,7 @@ impl RedisManager for StandardRedisManager return Ok(guard.clone()); } } + record_connection_reconnect("redis"); let mut connection_manager = (self.connect_func)().await?; let new_uuid = Uuid::new_v4(); self.configure(&mut connection_manager).await?; @@ -325,6 +340,7 @@ impl RedisManager for StandardRedisManager } async fn psubscribe(&self, pattern: &str) -> Result<(), Error> { + debug!(pattern, "new psubscribe"); let mut connection = self.get_connection().await?.0; let new_subscription = self.subscriptions.lock().insert(String::from(pattern)); if new_subscription { @@ -334,6 +350,7 @@ impl RedisManager for StandardRedisManager } result?; } + debug!(pattern, new_subscription, "new psubscribe complete"); Ok(()) } } @@ -386,10 +403,7 @@ where max_count_per_cursor: u64, /// A manager for subscriptions to keys in Redis. - subscription_manager: tokio::sync::OnceCell>, - - /// Channel for getting subscription messages - subscriber_channel: Mutex>>, + subscription_manager: Arc, /// Permits to limit inflight Redis requests. Technically only /// limits the calls to `get_client()`, but the requests per client @@ -398,6 +412,16 @@ where /// Per-call ceiling for `check_health` PING. health_check_timeout: Duration, + + /// Expire keys this store writes after this long. `None` keeps them + /// forever, which is the default and what every store other than a BEP + /// store wants. + key_ttl: Option, + + /// Have we done a subscribe for messages for `remove_callback` subscribes? + has_remove_callback_subscribe: OnceCell<()>, + + remove_callbacks: Arc>>, } impl Debug for RedisStore @@ -416,7 +440,6 @@ where ) .field("scan_count", &self.scan_count) .field("subscription_manager", &self.subscription_manager) - .field("subscriber_channel", &self.subscriber_channel) .field("client_permits", &self.client_permits) .finish() } @@ -447,6 +470,35 @@ impl Drop for ClientWithPermit { } } +/// Decode a `StoreKey` coming from Redis +pub fn decode_key<'a>( + key_prefix: &String, + encoded_key: Cow<'a, str>, +) -> Result, Error> { + let key_no_prefix = if key_prefix.is_empty() { + encoded_key + } else { + match encoded_key.strip_prefix(key_prefix) { + Some(r) => Cow::from(r.to_string()), + None => { + return Err(make_err!( + Code::InvalidArgument, + "Redis key ({}) is missing prefix ({})", + encoded_key, + key_prefix + )); + } + } + }; + let maybe_digest_info: Result<_, serde::de::value::Error> = + DigestInfo::deserialize(key_no_prefix.clone().into_deserializer()); + if let Ok(digest_info) = maybe_digest_info { + Ok(StoreKey::Digest(digest_info)) + } else { + Ok(StoreKey::Str(key_no_prefix)) + } +} + impl RedisStore where C: ConnectionLike + Clone + Sync, @@ -464,10 +516,20 @@ where max_client_permits: usize, max_count_per_cursor: u64, health_check_timeout: Duration, + key_ttl: Option, subscriber_channel: UnboundedReceiver, connection_manager: M, ) -> Result { info!("Redis index fingerprint: {FINGERPRINT_CREATE_INDEX_HEX}"); + let remove_callbacks = Arc::new(async_lock::Mutex::new(Vec::new())); + let subscription_manager = Arc::new(RedisSubscriptionManager::new( + subscriber_channel, + remove_callbacks.clone(), + key_prefix.clone(), + )); + if let Some(channel) = &pub_sub_channel { + connection_manager.psubscribe(channel).await?; + } Ok(Self { connection_manager, @@ -478,17 +540,22 @@ where read_chunk_size, max_chunk_uploads_per_update, scan_count, - subscription_manager: tokio::sync::OnceCell::new(), - subscriber_channel: Mutex::new(Some(subscriber_channel)), + subscription_manager, client_permits: Arc::new(Semaphore::new(max_client_permits)), max_count_per_cursor, health_check_timeout, + key_ttl, + has_remove_callback_subscribe: OnceCell::const_new(), + remove_callbacks, }) } async fn get_client(&self) -> Result, Error> { let local_client_permits = self.client_permits.clone(); let remaining = local_client_permits.available_permits(); + // Zero here means every client is busy and this call is about to wait, + // which is the saturation signal worth alerting on. + record_connection_acquired("redis", Some(remaining), remaining == 0); let semaphore_permit = local_client_permits.acquire_owned().await?; trace!(remaining, "Got a client permit"); let (connection_manager, uuid) = self.connection_manager.get_connection().await?; @@ -499,8 +566,8 @@ where }) } - /// Encode a [`StoreKey`] so it can be sent to Redis. - fn encode_key<'a>(&self, key: &'a StoreKey<'a>) -> Cow<'a, str> { + /// Encode a `StoreKey` so it can be sent to Redis. + pub fn encode_key<'a>(&self, key: &'a StoreKey<'a>) -> Cow<'a, str> { let key_body = key.as_str(); if self.key_prefix.is_empty() { key_body @@ -639,6 +706,7 @@ impl RedisStore> { spec.max_client_permits, spec.max_count_per_cursor, Duration::from_millis(spec.health_check_timeout_ms), + (spec.key_ttl_s > 0).then(|| Duration::from_secs(spec.key_ttl_s)), subscriber_channel, ClusterRedisManager::new(client.get_async_connection().await?).await?, ) @@ -712,12 +780,12 @@ impl RedisStore> { .await? .map_err(Into::::into), } - .err_tip_with_code(|_e| { - ( - Code::InvalidArgument, - format!("While connecting to redis with url: {local_addr}"), - ) - }) + // Keep the underlying error's code rather than forcing + // InvalidArgument. Not every connect failure is a bad URL: a + // sentinel failover in progress reports the master as missing, + // which is transient and retryable, and overriding it to a + // permanent status made clients give up on a recoverable blip. + .err_tip(|| format!("While connecting to redis with url: {local_addr}")) }), ) .await @@ -766,6 +834,7 @@ impl RedisStore> { spec.max_client_permits, spec.max_count_per_cursor, Duration::from_millis(spec.health_check_timeout_ms), + (spec.key_ttl_s > 0).then(|| Duration::from_secs(spec.key_ttl_s)), subscriber_channel, StandardRedisManager::new(Box::new(move || { Box::pin(Self::connect(spec.clone(), tx.clone())) @@ -913,19 +982,21 @@ where errors.push(format!("Non-utf8 key {raw_key:?}")); continue; }; - if let Some(key) = str_key.strip_prefix(&self.key_prefix) { - let key = StoreKey::new_str(key); - if range.contains(&key) { - iterations += 1; - if !handler(&key) { - error!("Issue in handler"); - errors.push("Issue in handler".to_string()); + match decode_key(&self.key_prefix, Cow::from(str_key)) { + Ok(key) => { + if range.contains(&key) { + iterations += 1; + if !handler(&key) { + error!("Issue in handler"); + errors.push("Issue in handler".to_string()); + } + } else { + trace!(%key, ?range, "Key not in range"); } - } else { - trace!(%key, ?range, "Key not in range"); } - } else { - errors.push("Key doesn't match prefix".to_string()); + Err(e) => { + errors.push(e.to_string()); + } } } Err(err) @@ -1041,6 +1112,29 @@ where return Err(error); } } + // Guard the temp key as soon as it exists. An update that + // dies anywhere after this — mid-upload, during the length + // check, during the rename — would otherwise leave the + // temp key behind forever, and nothing cleans those up. + // EXPIRE on a key that does not exist yet is a no-op, so + // this has to happen after the first chunk lands rather + // than before the loop. + if offset == 0 && let Some(key_ttl) = self.key_ttl { + let ttl_secs = ttl_seconds(key_ttl); + match connection_manager.expire::<_, ()>(temp_key_ref, ttl_secs).await { + Ok(()) => {} + Err(err) if is_retryable_redis_error(&err) => { + let (mut connection_manager, _connect_id) = self.connection_manager.reconnect(connect_id).await?; + connection_manager + .expire::<_, ()>(temp_key_ref, ttl_secs) + .await + .err_tip(|| format!("(after reconnect) while setting TTL on temp key ({temp_key_ref}) in RedisStore::update"))?; + } + Err(err) => { + return Err(Error::from(err).append(format!("While setting TTL on temp key ({temp_key_ref}) in RedisStore::update"))); + } + } + } Ok::(end_pos) }) }) @@ -1129,6 +1223,43 @@ where } } + // The rename carries the temp key's TTL across, so the key is never + // unprotected. Re-setting it here restarts the window at completion + // rather than at the first byte, which matters for a large blob whose + // upload takes a noticeable slice of the TTL. Reconnect once on a + // transient failover error, the same as the rename above: a key that + // silently never expires is the bug this option exists to prevent. + if let Some(key_ttl) = self.key_ttl { + let ttl_secs = ttl_seconds(key_ttl); + match client + .connection_manager + .expire::<_, ()>(final_key.as_ref(), ttl_secs) + .await + { + Ok(()) => {} + Err(err) if is_retryable_redis_error(&err) => { + let (connection_manager, uuid) = + self.connection_manager.reconnect(client.uuid).await?; + client.connection_manager = connection_manager; + client.uuid = uuid; + client + .connection_manager + .expire::<_, ()>(final_key.as_ref(), ttl_secs) + .await + .err_tip(|| { + format!( + "While setting TTL on {final_key} (after reconnect) in RedisStore::update()" + ) + })?; + } + Err(err) => { + return Err(Error::from(err).append(format!( + "While setting TTL on {final_key} in RedisStore::update()" + ))); + } + } + } + // If we have a publish channel configured, send a notice that the key has been set. if let Some(pub_sub_channel) = &self.pub_sub_channel { client @@ -1169,13 +1300,13 @@ where // We want to read the data at the key from `offset` to `offset + length`. let data_start = offset; let data_end = data_start - .saturating_add(length.unwrap_or(isize::MAX as usize) as isize) + .saturating_add(length.map_or(isize::MAX, |l| isize::try_from(l).unwrap_or(isize::MAX))) .saturating_sub(1); // And we don't ever want to read more than `read_chunk_size` bytes at a time, so we'll need to iterate. let mut chunk_start = data_start; let mut chunk_end = cmp::min( - data_start.saturating_add(self.read_chunk_size as isize) - 1, + data_start.saturating_add(self.read_chunk_size.try_into().unwrap_or(isize::MAX)) - 1, data_end, ); @@ -1233,7 +1364,8 @@ where // ...and go grab the next chunk. chunk_start = chunk_end + 1; chunk_end = cmp::min( - chunk_start.saturating_add(self.read_chunk_size as isize) - 1, + chunk_start.saturating_add(self.read_chunk_size.try_into().unwrap_or(isize::MAX)) + - 1, data_end, ); } @@ -1293,11 +1425,38 @@ where registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { - // As redis doesn't drop stuff, we can just ignore this + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { + debug!(?callback, "New callback"); + let local_self = self.clone(); + background_spawn!("remove_callback_subscribe", async move { + self.remove_callbacks.lock().await.push(callback); + if let Err(err) = local_self.clone().has_remove_callback_subscribe + .get_or_try_init(|| async move { + let mut client = local_self.get_client().await?; + let cfg = redis::cmd("CONFIG").arg("GET").arg("notify-keyspace-events").to_owned().query_async::>(&mut client.connection_manager).await.map_err(|e| Error::from(e).append("Parsing notify-keyspace-events"))?; + if cfg.len() != 1 { + warn!(?cfg, "Got multiple items for CONFIG GET, expected one"); + return Err(make_input_err!("Got multiple items for CONFIG GET, expected one")); + } + let events_cfg = &cfg.first().ok_or_else(|| make_err!(Code::InvalidArgument, "Only one item"))?.1; + if events_cfg.is_empty() { + error!("notify-keyspace-events not enabled for Redis, will fail to get remove callbacks"); + } else if !events_cfg.contains('K') { + error!(notify_keyspace_events=events_cfg, "notify-keyspace-events does not contain 'K' so won't get keyspace events we need for eviction events"); + } else if !events_cfg.contains('A') { + error!(notify_keyspace_events=events_cfg, "notify-keyspace-events does not contain 'A' so we won't get eviction events"); + } + // FIXME: Redis events spec appears unreliable, so we subscribe anyways + // It should just need Ke as per https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/ + // but I'm yet to get reliable eviction events out of that + info!(notify_keyspace_events=events_cfg, "Attempting to subscribe to eviction events"); + self.connection_manager.psubscribe("__key*__:*").await?; + Ok::<(), Error>(()) + }) + .await { + error!(?err, "Error while trying to initialise remove_callback_subscribe"); + } + }); Ok(()) } } @@ -1645,7 +1804,11 @@ pub struct RedisSubscriptionManager { } impl RedisSubscriptionManager { - pub fn new(subscriber_channel: UnboundedReceiver) -> Self { + pub fn new( + subscriber_channel: UnboundedReceiver, + remove_callbacks: Arc>>, + key_prefix: String, + ) -> Self { let subscribed_keys = Arc::new(RwLock::new(StringPatriciaMap::new())); let subscribed_keys_weak = Arc::downgrade(&subscribed_keys); let (tx_for_test, mut rx_for_test) = unbounded_channel(); @@ -1656,6 +1819,7 @@ impl RedisSubscriptionManager { _subscription_spawn: Arc::new(Mutex::new(spawn!( "redis_subscribe_spawn", async move { + debug!("running subscribe loop"); loop { loop { let key = select! { @@ -1682,7 +1846,7 @@ impl RedisSubscriptionManager { error!(?push_info, "Expected exactly 3 values on subscriber channel (pattern, channel, value)"); continue; } - match push_info.data.last().unwrap() { + let value = match push_info.data.last().unwrap() { Value::SimpleString(s) => { s.clone() } @@ -1693,7 +1857,49 @@ impl RedisSubscriptionManager { error!(?other, "Received non-string message in RedisSubscriptionManager"); continue; } + }; + // Redis reports maxmemory eviction as + // "evicted" and TTL expiry as "expired". + // Both mean the key is gone, so both have + // to invalidate anything caching its + // existence; treating only one as a removal + // leaves an ExistenceCacheStore claiming to + // hold a key that Redis has already dropped. + if value == "evicted" || value == "expired" { + trace!(?push_info, %value, "Key removal event"); + let removed_key = if let Some(key) = push_info.data.get(1) { + if let Value::BulkString(s) = key { + String::from_utf8(s.clone()).expect("String message") + } else { + error!(?push_info, "Removed key wasn't bulk-string"); + continue; + } + } else { + error!(?push_info, "No key in removal event"); + continue; + }; + trace!(?removed_key, "Removed key"); + let Some((_prefix, internal_key)) = removed_key.split_once(':') else { + error!(?removed_key, "Removed key doesn't contain a colon"); + continue; + }; + + let store_key = match decode_key(&key_prefix, Cow::from(internal_key)) { + Ok(k) => k.into_owned(), + Err(err) => { + error!(%err, internal_key, "Bad redis key"); + continue; + } + }; + let locked_remove_callbacks = remove_callbacks.lock().await; + let mut callbacks: FuturesUnordered<_> = + locked_remove_callbacks.iter() + .map(|callback| callback.callback(store_key.borrow())) + .collect(); + while callbacks.next().await.is_some() {} + continue } + value } else { error!("Error receiving message in RedisSubscriptionManager from subscriber_channel"); break; @@ -1786,23 +1992,12 @@ where type SubscriptionManager = RedisSubscriptionManager; async fn subscription_manager(&self) -> Result, Error> { - self.subscription_manager - .get_or_try_init(|| async move { - let Some(subscriber_channel) = self.subscriber_channel.lock().take() else { - return Err(make_input_err!( - "Multiple attempts to obtain the subscription manager in RedisStore" - )); - }; - let Some(pub_sub_channel) = &self.pub_sub_channel else { - return Err(make_input_err!( - "RedisStore must have a pubsub for Redis Scheduler if using subscriptions" - )); - }; - self.connection_manager.psubscribe(pub_sub_channel).await?; - Ok(Arc::new(RedisSubscriptionManager::new(subscriber_channel))) - }) - .await - .map(Clone::clone) + if self.pub_sub_channel.is_none() { + return Err(make_input_err!( + "RedisStore must have a pubsub for Redis Scheduler if using subscriptions" + )); + } + Ok(self.subscription_manager.clone()) } async fn update_data(&self, data: T, expiry: Option) -> Result, Error> diff --git a/nativelink-store/src/redis_utils/ft_aggregate.rs b/nativelink-store/src/redis_utils/ft_aggregate.rs index c99250378..07a353a69 100644 --- a/nativelink-store/src/redis_utils/ft_aggregate.rs +++ b/nativelink-store/src/redis_utils/ft_aggregate.rs @@ -264,12 +264,25 @@ fn resp3_data_parse( }; match map_key.as_str() { "extra_attributes" => { - let Value::Map(extra_attributes_values) = raw_map_value else { - return Err(RedisError::from(( - ErrorKind::Parse, - "Expected Map for extra_attributes", - format!("{raw_map_value:?}"), - ))); + let extra_attributes_values = match raw_map_value { + Value::Map(extra_attributes_values) => extra_attributes_values, + // A document that expired or was deleted between + // the search phase and the load phase comes back + // as a row with Nil attributes. Under load this is + // routine — completed awaited-action records expire + // constantly — so drop the row instead of failing + // the whole aggregate. Failing here surfaced to + // clients as `INVALID_ARGUMENT`, which Bazel treats + // as permanent, so a single expiry race killed the + // build. + Value::Nil => continue, + other => { + return Err(RedisError::from(( + ErrorKind::Parse, + "Expected Map for extra_attributes", + format!("{other:?}"), + ))); + } }; let mut output_array = vec![]; for (e_key, e_value) in extra_attributes_values { diff --git a/nativelink-store/src/ref_store.rs b/nativelink-store/src/ref_store.rs index c6100db8f..26c15678b 100644 --- a/nativelink-store/src/ref_store.rs +++ b/nativelink-store/src/ref_store.rs @@ -23,7 +23,7 @@ use nativelink_metric::MetricsComponent; use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use parking_lot::Mutex; use tracing::{debug, error}; @@ -48,7 +48,7 @@ pub struct RefStore { name: String, store_manager: Weak, inner: StoreReference, - remove_callbacks: Mutex>>, + remove_callbacks: Mutex>, } impl RefStore { @@ -159,10 +159,7 @@ impl StoreDriver for RefStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.remove_callbacks.lock().push(callback.clone()); let ref_store = self.inner.cell.0.get(); unsafe { diff --git a/nativelink-store/src/s3_store.rs b/nativelink-store/src/s3_store.rs index 5c2d3837e..a055ace3c 100644 --- a/nativelink-store/src/s3_store.rs +++ b/nativelink-store/src/s3_store.rs @@ -47,7 +47,7 @@ use nativelink_util::health_utils::{HealthRegistryBuilder, HealthStatus, HealthS use nativelink_util::instant_wrapper::InstantWrapper; use nativelink_util::retry::{Retrier, RetryResult}; use nativelink_util::store_trait::{ - RemoveItemCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, + RemoveCallback, StoreDriver, StoreKey, StoreOptimizations, UploadSizeInfo, }; use parking_lot::Mutex; use tokio::sync::mpsc; @@ -98,7 +98,7 @@ pub struct S3Store { #[metric(help = "The number of concurrent uploads allowed for multipart uploads")] multipart_max_concurrent_uploads: usize, - remove_callbacks: Mutex>>, + remove_callbacks: Mutex>, } impl S3Store @@ -110,12 +110,13 @@ where let jitter_fn = spec.common.retry.make_jitter_fn(); let s3_client = { let http_client = TlsClient::new(&spec.common.clone()); + let credential_http_client = TlsClient::new_for_credentials(&spec.common); let credential_provider = credentials::DefaultCredentialsChain::builder() .configure( ProviderConfig::without_region() .with_region(Some(Region::new(Cow::Owned(spec.region.clone())))) - .with_http_client(http_client.clone()), + .with_http_client(credential_http_client), ) .build() .await; @@ -195,7 +196,10 @@ where if self.consider_expired_after_s != 0 && let Some(last_modified) = head_object_output.last_modified { - let now_s = (self.now_fn)().unix_timestamp() as i64; + let now_s = (self.now_fn)() + .unix_timestamp() + .try_into() + .unwrap_or(i64::MAX); if last_modified.secs() + self.consider_expired_after_s <= now_s { let remove_callbacks = self.remove_callbacks.lock().clone(); let mut callbacks: FuturesUnordered<_> = remove_callbacks @@ -323,7 +327,7 @@ where .put_object() .bucket(&self.bucket) .key(s3_path.clone()) - .content_length(sz as i64) + .content_length(sz.try_into().unwrap_or(i64::MAX)) .body(ByteStream::from_body_1_x(BodyWrapper { reader: rx, size: sz, @@ -684,10 +688,7 @@ where registry.register_indicator(self); } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.remove_callbacks.lock().push(callback); Ok(()) } diff --git a/nativelink-store/src/shard_store.rs b/nativelink-store/src/shard_store.rs index 6855d3a96..2f2494481 100644 --- a/nativelink-store/src/shard_store.rs +++ b/nativelink-store/src/shard_store.rs @@ -27,7 +27,7 @@ use nativelink_metric::MetricsComponent; use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; #[derive(Debug, MetricsComponent)] @@ -40,7 +40,7 @@ struct StoreAndWeight { #[derive(Debug, MetricsComponent)] pub struct ShardStore { - // The weights will always be in ascending order a specific store is chosen based on the + // The weights will always be in ascending order a specific store is chosen based on // the hash of the key hash that is nearest-binary searched using the u32 as the index. #[metric( group = "stores", @@ -254,10 +254,7 @@ impl StoreDriver for ShardStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { for store in &self.weights_and_stores { store.store.register_remove_callback(callback.clone())?; } diff --git a/nativelink-store/src/size_partitioning_store.rs b/nativelink-store/src/size_partitioning_store.rs index 883530078..b9883e423 100644 --- a/nativelink-store/src/size_partitioning_store.rs +++ b/nativelink-store/src/size_partitioning_store.rs @@ -23,7 +23,7 @@ use nativelink_metric::MetricsComponent; use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use tokio::join; @@ -171,10 +171,7 @@ impl StoreDriver for SizePartitioningStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.lower_store .register_remove_callback(callback.clone())?; self.upper_store.register_remove_callback(callback)?; diff --git a/nativelink-store/src/store_manager.rs b/nativelink-store/src/store_manager.rs index 9920a012c..919f05838 100644 --- a/nativelink-store/src/store_manager.rs +++ b/nativelink-store/src/store_manager.rs @@ -14,7 +14,7 @@ use std::collections::HashMap; -use nativelink_error::Error; +use nativelink_error::{Code, Error, make_err}; use nativelink_metric::{MetricsComponent, RootMetricsComponent}; use nativelink_util::store_trait::Store; use parking_lot::RwLock; @@ -32,9 +32,16 @@ impl StoreManager { } } - pub fn add_store(&self, name: &str, store: Store) { + pub fn add_store(&self, name: &str, store: Store) -> Result<(), Error> { let mut stores = self.stores.write(); + if stores.contains_key(name) { + return Err(make_err!( + Code::AlreadyExists, + "Store name '{name}' already exists in the store manager" + )); + } stores.insert(name.to_string(), store); + Ok(()) } pub fn get_store(&self, name: &str) -> Option { diff --git a/nativelink-store/src/verify_store.rs b/nativelink-store/src/verify_store.rs index e3722ff48..f42587aeb 100644 --- a/nativelink-store/src/verify_store.rs +++ b/nativelink-store/src/verify_store.rs @@ -23,13 +23,14 @@ use nativelink_util::buf_channel::{ DropCloserReadHalf, DropCloserWriteHalf, make_buf_channel_pair, }; use nativelink_util::common::PackedHash; -use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc, default_digest_hasher_func}; +use nativelink_util::digest_hasher::{ + DigestHasher, DigestHasherFunc, digest_hasher_func_from_context, +}; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::metrics_utils::CounterWithTime; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; -use opentelemetry::context::Context; #[derive(Debug, MetricsComponent)] pub struct VerifyStore { @@ -64,6 +65,7 @@ impl VerifyStore { mut rx: DropCloserReadHalf, maybe_expected_digest_size: Option, original_hash: &PackedHash, + digest_function: Option, mut maybe_hasher: Option<&mut D>, ) -> Result { let mut sum_size: u64 = 0; @@ -120,8 +122,13 @@ impl VerifyStore { let hash_result = digest.packed_hash(); if original_hash != hash_result { self.hash_verification_failures.inc(); + let Some(digest_function) = digest_function else { + return Err(make_input_err!( + "Hash verification failed without a digest function" + )); + }; return Err(make_input_err!( - "Hashes do not match, got: {original_hash} but digest hash was {hash_result}", + "Hash verification using {digest_function} failed: client declared {digest_function}:{original_hash}, but the server computed {digest_function}:{hash_result}", )); } } @@ -183,16 +190,12 @@ impl StoreDriver for VerifyStore { )); } - let mut hasher = if self.verify_hash { - Some( - Context::current() - .get::() - .map_or_else(default_digest_hasher_func, |v| *v) - .hasher(), - ) + let digest_function = if self.verify_hash { + Some(digest_hasher_func_from_context()) } else { None }; + let mut hasher = digest_function.map(|digest_function| digest_function.hasher()); let maybe_digest_size = if self.verify_size { Some(digest_size) @@ -207,6 +210,7 @@ impl StoreDriver for VerifyStore { reader, maybe_digest_size, digest.packed_hash(), + digest_function, hasher.as_mut(), ); @@ -241,10 +245,7 @@ impl StoreDriver for VerifyStore { self } - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error> { self.inner_store.register_remove_callback(callback) } } diff --git a/nativelink-store/tests/azure_blob_store_test.rs b/nativelink-store/tests/azure_blob_store_test.rs index e3ace7921..fbc773b40 100644 --- a/nativelink-store/tests/azure_blob_store_test.rs +++ b/nativelink-store/tests/azure_blob_store_test.rs @@ -12,18 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use core::fmt::{Debug, Formatter}; use core::sync::atomic::{AtomicUsize, Ordering}; use core::time::Duration; +use std::collections::VecDeque; use std::sync::{Arc, Mutex}; -use azure_core::{HttpClient, StatusCode, TransportOptions, base64}; -use azure_storage::StorageCredentials; -use azure_storage_blobs::prelude::*; -use base64::encode; +use azure_core::error::ErrorKind; +use azure_core::http::headers::Headers; +use azure_core::http::{ + AsyncRawResponse, HttpClient, Method, Request, RetryOptions, StatusCode, Transport, Url, +}; +use azure_storage_blob::clients::{BlobContainerClient, BlobContainerClientOptions}; use bytes::{BufMut, Bytes, BytesMut}; -use nativelink_config::stores::ExperimentalAzureSpec; -use nativelink_error::{Error, ResultExt}; +use nativelink_config::stores::{CommonObjectSpec, ExperimentalAzureSpec, Retry}; +use nativelink_error::{Code, Error, ResultExt}; use nativelink_macro::nativelink_test; use nativelink_store::azure_blob_store::AzureBlobStore; use nativelink_util::buf_channel::make_buf_channel_pair; @@ -32,288 +34,315 @@ use nativelink_util::instant_wrapper::MockInstantWrapped; use nativelink_util::store_trait::{StoreKey, StoreLike, UploadSizeInfo}; use sha2::{Digest, Sha256}; -// Test constants const TEST_CONTAINER: &str = "test-container"; const TEST_ACCOUNT: &str = "testaccount"; -const TEST_KEY: &str = "dGVzdGtleQ=="; // base64 encoded "testkey" const TEST_HASH: &str = "0000000000000000000000000000000000000000000000000000000000000000"; const TEST_SIZE: u64 = 100; -type AzureBlobStoreTest = Arc MockInstantWrapped>>; +const EPOCH_LAST_MODIFIED: &str = "Thu, 01 Jan 1970 00:00:00 GMT"; -/// Test utilities -mod test_utils { - use core::default::Default; +type TestStore = Arc MockInstantWrapped>>; - use nativelink_config::stores::CommonObjectSpec; - - use super::*; +/// A single canned HTTP response the mock transport hands back to the SDK. +#[derive(Clone, Debug)] +struct CannedResponse { + status: StatusCode, + headers: Vec<(&'static str, String)>, + body: Vec, +} - #[derive(Debug)] - pub(crate) struct TestResponse { - pub status: StatusCode, - pub headers: Vec<(&'static str, String)>, - pub body: Vec, +fn properties_ok(content_length: u64) -> CannedResponse { + CannedResponse { + status: StatusCode::Ok, + headers: vec![ + ("content-length", content_length.to_string()), + ("last-modified", EPOCH_LAST_MODIFIED.to_string()), + ], + body: Vec::new(), } +} - impl TestResponse { - pub(crate) fn ok() -> Self { - Self { - status: StatusCode::Ok, - // A sample set of headers. - headers: vec![ - ("content-length", "0".to_string()), - ("last-modified", "Thu, 01 Jan 1970 00:00:00 GMT".to_string()), - ("etag", "\"test-etag\"".to_string()), - ( - "x-ms-creation-time", - "Thu, 01 Jan 1970 00:00:00 GMT".to_string(), - ), - ("x-ms-lease-status", "unlocked".to_string()), - ("x-ms-lease-state", "available".to_string()), - ("x-ms-blob-type", "BlockBlob".to_string()), - ("x-ms-server-encrypted", "true".to_string()), - ("x-ms-request-server-encrypted", "true".to_string()), - ("x-ms-blob-committed-block-count", "0".to_string()), - ("x-ms-blob-content-encoding", "utf-8".to_string()), - ( - "x-ms-request-id", - "00000000-0000-0000-0000-000000000000".to_string(), - ), - ("x-ms-version", "2020-04-08".to_string()), - ("date", "Thu, 01 Jan 1970 00:00:00 GMT".to_string()), - ], - body: vec![], - } - } - - pub(crate) const fn error(status: StatusCode) -> Self { - Self { - status, - headers: vec![], - body: vec![], - } - } - - pub(crate) const fn not_found() -> Self { - Self::error(StatusCode::NotFound) - } +const fn error_response(status: StatusCode) -> CannedResponse { + CannedResponse { + status, + headers: Vec::new(), + body: Vec::new(), + } +} - pub(crate) fn with_content_length(mut self, length: usize) -> Self { - if let Some(header) = self - .headers - .iter_mut() - .find(|(key, _)| *key == "content-length") - { - header.1 = length.to_string(); - } else { - self.headers.push(("content-length", length.to_string())); - } - self - } +const fn not_found() -> CannedResponse { + error_response(StatusCode::NotFound) +} - pub(crate) fn with_body(mut self, body: Vec) -> Self { - self.body = body; - self - } +/// Successful write result for the SDK upload/stage/commit operations. +const fn created() -> CannedResponse { + CannedResponse { + status: StatusCode::Created, + headers: Vec::new(), + body: Vec::new(), } +} - #[derive(Debug)] - pub(crate) struct TestRequest { - pub method: &'static str, - pub url_pattern: String, - pub response: TestResponse, +fn download_ok(status: StatusCode, body: Vec) -> CannedResponse { + CannedResponse { + status, + headers: vec![("content-length", body.len().to_string())], + body, } +} - impl TestRequest { - pub(crate) const fn new( - method: &'static str, - url_pattern: String, - response: TestResponse, - ) -> Self { - Self { - method, - url_pattern, - response, - } - } +/// Fake [`HttpClient`] injected into the SDK pipeline. It routes on the request's +/// method and the `comp` query parameter to mirror how the store calls the SDK: +/// * HEAD -> `get_properties` +/// * GET -> `download` (range is carried in a header) +/// * PUT `?comp=block` -> stage a block +/// * PUT `?comp=blocklist`-> commit the block list +/// * PUT (no `comp`) -> single-shot block-blob upload +/// +/// Each operation has its own queue of responses consumed in order, which lets the +/// retry tests assert the exact request sequence. +#[derive(Debug, Default)] +struct MockTransport { + properties: Mutex>, + download: Mutex>, + upload: Mutex>, + stage_block: Mutex>, + commit: Mutex>, + /// Raw XML body of the last `commit_block_list` request (the committed block + /// list), captured so tests can assert the exact set/order of block ids. + committed_block_list: Mutex>, + count: AtomicUsize, +} - pub(crate) fn head(digest: &str, size: u64, response: TestResponse) -> Self { - Self::new( - "HEAD", - format!("{TEST_CONTAINER}/{digest}-{size}"), - response, - ) - } +impl MockTransport { + fn new() -> Arc { + Arc::new(Self::default()) + } - pub(crate) fn get(digest: &str, size: u64, response: TestResponse) -> Self { - Self::new("GET", format!("{TEST_CONTAINER}/{digest}-{size}"), response) - } + fn push_properties(&self, response: CannedResponse) { + self.properties.lock().unwrap().push_back(response); + } - pub(crate) fn put(digest: &str, size: u64, response: TestResponse) -> Self { - Self::new("PUT", format!("{TEST_CONTAINER}/{digest}-{size}"), response) - } + fn push_download(&self, response: CannedResponse) { + self.download.lock().unwrap().push_back(response); } - #[derive(Clone)] - pub(crate) struct MockAzureClient { - expected_requests: Arc>, - current_request: Arc, - request_log: Arc>>, + fn push_upload(&self, response: CannedResponse) { + self.upload.lock().unwrap().push_back(response); } - impl Debug for MockAzureClient { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("MockAzureClient") - .field("current_request", &self.current_request) - .field("request_count", &self.request_log.lock().unwrap().len()) - .finish() - } + fn request_count(&self) -> usize { + self.count.load(Ordering::SeqCst) } - impl MockAzureClient { - pub(crate) fn new(requests: Vec) -> Self { - Self { - expected_requests: Arc::new(requests), - current_request: Arc::new(AtomicUsize::new(0)), - request_log: Arc::new(Mutex::new(Vec::new())), - } - } + fn committed_block_list(&self) -> Option { + self.committed_block_list.lock().unwrap().clone() + } - pub(crate) fn request_count(&self) -> usize { - self.request_log.lock().unwrap().len() - } + fn pop(queue: &Mutex>) -> Option { + queue.lock().unwrap().pop_front() + } +} - pub(crate) fn single_head_request(response: TestResponse) -> Self { - Self::new(vec![TestRequest::head(TEST_HASH, TEST_SIZE, response)]) - } +fn build_response(canned: CannedResponse) -> AsyncRawResponse { + let mut headers = Headers::new(); + for (key, value) in canned.headers { + headers.insert(key, value); } + AsyncRawResponse::from_bytes(canned.status, headers, canned.body) +} - #[async_trait::async_trait] - impl HttpClient for MockAzureClient { - async fn execute_request( - &self, - request: &azure_core::Request, - ) -> azure_core::Result { - self.request_log.lock().unwrap().push(request.clone()); - - let index = self.current_request.fetch_add(1, Ordering::SeqCst); - let expected = &self.expected_requests[index]; - - if request.method().to_string() != expected.method - || !request.url().as_str().contains(&expected.url_pattern) - { - return Err(azure_core::Error::new( - azure_core::error::ErrorKind::Other, - format!("Unexpected request: {} {}", request.method(), request.url()), - )); - } +#[async_trait::async_trait] +impl HttpClient for MockTransport { + async fn execute_request(&self, request: &Request) -> azure_core::Result { + self.count.fetch_add(1, Ordering::SeqCst); - let mut headers = azure_core::headers::Headers::new(); - for (key, value) in &expected.response.headers { - headers.insert(*key, value); + let query = request.url().query().unwrap_or_default().to_owned(); + let canned = match request.method() { + Method::Head => Self::pop(&self.properties).unwrap_or_else(|| properties_ok(0)), + Method::Get => { + Self::pop(&self.download).unwrap_or_else(|| download_ok(StatusCode::Ok, Vec::new())) + } + Method::Put if query.contains("comp=blocklist") => { + *self.committed_block_list.lock().unwrap() = Some(Bytes::from(request.body())); + Self::pop(&self.commit).unwrap_or_else(created) } + Method::Put if query.contains("comp=block") => { + Self::pop(&self.stage_block).unwrap_or_else(created) + } + Method::Put => Self::pop(&self.upload).unwrap_or_else(created), + other => { + return Err(azure_core::Error::with_message( + ErrorKind::Other, + format!("Unexpected request: {other} {}", request.url()), + )); + } + }; - let body = expected.response.body.clone(); - Ok(azure_core::Response::new( - expected.response.status, - headers, - Box::pin(futures::stream::once(async move { Ok(Bytes::from(body)) })), - )) - } + Ok(build_response(canned)) } +} - pub(crate) fn create_test_store( - client: MockAzureClient, - retry_config: Option, - consider_expired_after_s: Option, - ) -> Result { - let transport = TransportOptions::new(Arc::new(client)); - let credentials = StorageCredentials::access_key( - TEST_ACCOUNT.to_string(), - azure_core::auth::Secret::new(TEST_KEY.to_string()), - ); - - let container_client = BlobServiceClient::builder(TEST_ACCOUNT, credentials) - .transport(transport) - .container_client(TEST_CONTAINER); - - let spec = ExperimentalAzureSpec { - account_name: TEST_ACCOUNT.to_string(), - container: TEST_CONTAINER.to_string(), - common: CommonObjectSpec { - consider_expired_after_s: consider_expired_after_s.unwrap_or(0), - retry: retry_config.unwrap_or_default(), - ..Default::default() - }, +fn create_test_store( + mock: Arc, + retry: Option, + consider_expired_after_s: Option, +) -> Result { + let mut options = BlobContainerClientOptions::default(); + // NativeLink's own `Retrier` wraps each operation, so disable the SDK's retry + // policy to keep request counts deterministic. + options.client_options.retry = RetryOptions::none(); + options.client_options.transport = Some(Transport::new(mock)); + + let container_url = Url::parse(&format!( + "https://{TEST_ACCOUNT}.blob.core.windows.net/{TEST_CONTAINER}" + )) + .expect("valid container URL"); + let client = BlobContainerClient::new(container_url, None, Some(options)) + .expect("failed to build BlobContainerClient"); + + let spec = ExperimentalAzureSpec { + account_name: TEST_ACCOUNT.to_string(), + container: TEST_CONTAINER.to_string(), + common: CommonObjectSpec { + consider_expired_after_s: consider_expired_after_s.unwrap_or(0), + retry: retry.unwrap_or_default(), ..Default::default() - }; - - AzureBlobStore::new_with_client_and_jitter( - &spec, - container_client, - Arc::new(|_| Duration::from_secs(0)), - MockInstantWrapped::default, - ) - } + }, + ..Default::default() + }; - pub(crate) fn create_test_digest() -> Result { - DigestInfo::try_new(TEST_HASH, TEST_SIZE) - } + AzureBlobStore::new_with_client_and_jitter( + &spec, + client, + Arc::new(|_| Duration::from_secs(0)), + MockInstantWrapped::default, + ) } -use test_utils::*; +fn create_test_digest() -> Result { + DigestInfo::try_new(TEST_HASH, TEST_SIZE) +} #[nativelink_test] async fn test_has_object_found() -> Result<(), Error> { - let client = MockAzureClient::single_head_request(TestResponse::ok().with_content_length(512)); - let store = create_test_store(client.clone(), None, None)?; + let mock = MockTransport::new(); + mock.push_properties(properties_ok(512)); + let store = create_test_store(Arc::clone(&mock), None, None)?; let result = store.has(create_test_digest()?).await?; assert_eq!(result, Some(512)); - assert_eq!(client.request_count(), 1); + assert_eq!(mock.request_count(), 1); Ok(()) } #[nativelink_test] async fn test_has_object_not_found() -> Result<(), Error> { - let client = MockAzureClient::single_head_request(TestResponse::not_found()); - let store = create_test_store(client.clone(), None, None)?; + let mock = MockTransport::new(); + mock.push_properties(not_found()); + let store = create_test_store(Arc::clone(&mock), None, None)?; let result = store.has(create_test_digest()?).await?; assert_eq!(result, None); - assert_eq!(client.request_count(), 1); + assert_eq!(mock.request_count(), 1); Ok(()) } #[nativelink_test] async fn test_has_with_retries() -> Result<(), Error> { - let client = MockAzureClient::new(vec![ - TestRequest::head( - TEST_HASH, - TEST_SIZE, - TestResponse::error(StatusCode::InternalServerError), - ), - TestRequest::head( - TEST_HASH, - TEST_SIZE, - TestResponse::ok().with_content_length(111), - ), - ]); - - let retry_config = nativelink_config::stores::Retry { + let mock = MockTransport::new(); + mock.push_properties(error_response(StatusCode::InternalServerError)); + mock.push_properties(properties_ok(111)); + + let retry = Retry { max_retries: 3, delay: 0.0, jitter: 0.0, ..Default::default() }; - let store = create_test_store(client.clone(), Some(retry_config), None)?; + let store = create_test_store(Arc::clone(&mock), Some(retry), None)?; let result = store.has(create_test_digest()?).await?; assert_eq!(result, Some(111)); - assert_eq!(client.request_count(), 2); + assert_eq!(mock.request_count(), 2); + Ok(()) +} + +#[nativelink_test] +async fn test_has_with_results_zero_digest() -> Result<(), Error> { + let digest = DigestInfo::new(Sha256::new().finalize().into(), 0); + let keys = vec![StoreKey::from(&digest)]; + let mut results = vec![None]; + + let mock = MockTransport::new(); + let store = create_test_store(Arc::clone(&mock), None, None)?; + + store.has_with_results(&keys, &mut results).await?; + + assert_eq!(results, vec![Some(0)]); + assert_eq!( + mock.request_count(), + 0, + "Expected no requests for zero digest" + ); + Ok(()) +} + +#[nativelink_test] +async fn test_has_with_expired_result() -> Result<(), Error> { + use mock_instant::thread_local::MockClock; + + const CONTENT_SIZE: usize = 10; + + let mock = MockTransport::new(); + mock.push_properties(properties_ok(512)); + mock.push_properties(properties_ok(512)); + + let store = create_test_store( + Arc::clone(&mock), + Some(Retry { + max_retries: 1, + delay: 0.0, + jitter: 0.0, + ..Default::default() + }), + Some(2 * 24 * 60 * 60), + )?; + + // Time starts at 1970-01-01 00:00:00 and the blob is last-modified at the epoch. + let digest = DigestInfo::try_new(TEST_HASH, CONTENT_SIZE)?; + + // 1 day in: not expired. + { + MockClock::advance(Duration::from_hours(24)); + let mut results = vec![None]; + store + .has_with_results(&[digest.into()], &mut results) + .await?; + assert_eq!( + results, + vec![Some(512)], + "Should find non-expired content after 1 day" + ); + } + + // 4 days in: expired (older than the 2-day threshold). + { + MockClock::advance(Duration::from_hours(3 * 24)); + let mut results = vec![None]; + store + .has_with_results(&[digest.into()], &mut results) + .await?; + assert_eq!( + results, + vec![None], + "Should not find expired content after 4 days" + ); + } + + assert_eq!(mock.request_count(), 2); Ok(()) } @@ -321,19 +350,55 @@ async fn test_has_with_retries() -> Result<(), Error> { async fn test_get() -> Result<(), Error> { const VALUE: &str = "test_content"; - let client = MockAzureClient::new(vec![TestRequest::get( - TEST_HASH, - TEST_SIZE, - TestResponse::ok().with_body(VALUE.as_bytes().to_vec()), - )]); + let mock = MockTransport::new(); + mock.push_download(download_ok(StatusCode::Ok, VALUE.as_bytes().to_vec())); - let store = create_test_store(client.clone(), None, None)?; + let store = create_test_store(Arc::clone(&mock), None, None)?; let result = store .get_part_unchunked(create_test_digest()?, 0, None) .await?; assert_eq!(result, VALUE.as_bytes()); - assert_eq!(client.request_count(), 1); + assert_eq!(mock.request_count(), 1); + Ok(()) +} + +#[nativelink_test] +async fn test_get_byte_range() -> Result<(), Error> { + const VALUE: &str = "0123456789abcdef"; + const OFFSET: u64 = 4; + const LENGTH: u64 = 6; + let start = usize::try_from(OFFSET).unwrap(); + let end = usize::try_from(OFFSET + LENGTH).unwrap(); + let expected = &VALUE.as_bytes()[start..end]; + + let mock = MockTransport::new(); + // A 206 Partial Content with just the requested slice as the body. + mock.push_download(download_ok(StatusCode::PartialContent, expected.to_vec())); + + let store = create_test_store(Arc::clone(&mock), None, None)?; + let result = store + .get_part_unchunked(create_test_digest()?, OFFSET, Some(LENGTH)) + .await?; + + assert_eq!(result, expected); + assert_eq!(mock.request_count(), 1); + Ok(()) +} + +#[nativelink_test] +async fn test_get_not_found() -> Result<(), Error> { + let mock = MockTransport::new(); + mock.push_download(not_found()); + + let store = create_test_store(Arc::clone(&mock), None, None)?; + let err = store + .get_part_unchunked(create_test_digest()?, 0, None) + .await + .expect_err("expected a NotFound error"); + + assert_eq!(err.code, Code::NotFound); + assert_eq!(mock.request_count(), 1); Ok(()) } @@ -341,72 +406,74 @@ async fn test_get() -> Result<(), Error> { async fn test_get_with_retries() -> Result<(), Error> { const VALUE: &str = "test_content"; - let client = MockAzureClient::new(vec![ - TestRequest::get( - TEST_HASH, - TEST_SIZE, - TestResponse::error(StatusCode::InternalServerError), - ), - TestRequest::get( - TEST_HASH, - TEST_SIZE, - TestResponse::error(StatusCode::ServiceUnavailable), - ), - TestRequest::get( - TEST_HASH, - TEST_SIZE, - TestResponse::error(StatusCode::Conflict), - ), - TestRequest::get( - TEST_HASH, - TEST_SIZE, - TestResponse::ok().with_body(VALUE.as_bytes().to_vec()), - ), - ]); - - let retry_config = nativelink_config::stores::Retry { + let mock = MockTransport::new(); + mock.push_download(error_response(StatusCode::InternalServerError)); + mock.push_download(error_response(StatusCode::ServiceUnavailable)); + mock.push_download(error_response(StatusCode::Conflict)); + mock.push_download(download_ok(StatusCode::Ok, VALUE.as_bytes().to_vec())); + + let retry = Retry { max_retries: 1024, delay: 0.0, jitter: 0.0, ..Default::default() }; - let store = create_test_store(client.clone(), Some(retry_config), None)?; + let store = create_test_store(Arc::clone(&mock), Some(retry), None)?; let result = store .get_part_unchunked(create_test_digest()?, 0, None) .await?; assert_eq!(result, VALUE.as_bytes()); - assert_eq!(client.request_count(), 4); + assert_eq!(mock.request_count(), 4); + Ok(()) +} + +#[nativelink_test] +async fn test_get_part_zero_digest() -> Result<(), Error> { + let digest = DigestInfo::new(Sha256::new().finalize().into(), 0); + let mock = MockTransport::new(); + let store = create_test_store(Arc::clone(&mock), None, None)?; + let (mut writer, mut reader) = make_buf_channel_pair(); + + let (get_result, file_data) = tokio::join!( + store.get_part(digest, &mut writer, 0, None), + reader.consume(Some(1024)) + ); + + get_result?; + let file_data = file_data.err_tip(|| "Error reading bytes")?; + + assert_eq!(file_data.len(), 0, "Expected empty file content"); + assert_eq!( + mock.request_count(), + 0, + "Expected no requests for zero digest" + ); Ok(()) } #[nativelink_test] async fn test_update_small_file() -> Result<(), Error> { - const CONTENT_LENGTH: usize = 1024; // Small enough for single block upload (<5MB). + const CONTENT_LENGTH: usize = 1024; // Below DEFAULT_BLOCK_SIZE: single-shot upload. let mut send_data = BytesMut::new(); for i in 0..CONTENT_LENGTH { send_data.put_u8(u8::try_from((i % 93) + 33).unwrap()); } let send_data = send_data.freeze(); - let client = MockAzureClient::new(vec![TestRequest::put( - TEST_HASH, - TEST_SIZE, - TestResponse::ok(), - )]); + let mock = MockTransport::new(); + mock.push_upload(created()); - let store = create_test_store(client.clone(), None, None)?; + let store = create_test_store(Arc::clone(&mock), None, None)?; let (mut tx, rx) = make_buf_channel_pair(); - // Starting the update futures let update_fut = store.update( create_test_digest()?, rx, UploadSizeInfo::ExactSize(CONTENT_LENGTH as u64), ); - // Sending the data in smaller chunks to test streaming let send_data_copy = send_data.clone(); let send_fut = Box::pin(async move { const CHUNK_SIZE: usize = 256; @@ -416,23 +483,21 @@ async fn test_update_small_file() -> Result<(), Error> { tx.send_eof() }); - // Waiting for both futures to complete let (update_result, send_result) = tokio::join!(update_fut, send_fut); update_result?; send_result?; - assert_eq!(client.request_count(), 1); + assert_eq!(mock.request_count(), 1); Ok(()) } #[nativelink_test] async fn test_update_zero_size() -> Result<(), Error> { - let client = MockAzureClient::new(vec![]); // Should not make any requests - let store = create_test_store(client.clone(), None, None)?; + let mock = MockTransport::new(); + let store = create_test_store(Arc::clone(&mock), None, None)?; let (mut tx, rx) = make_buf_channel_pair(); let update_fut = store.update(create_test_digest()?, rx, UploadSizeInfo::ExactSize(0)); - let send_fut = async move { tx.send_eof() }; let (update_result, send_result) = tokio::join!(update_fut, send_fut); @@ -440,7 +505,7 @@ async fn test_update_zero_size() -> Result<(), Error> { update_result?; send_result?; assert_eq!( - client.request_count(), + mock.request_count(), 0, "Zero-size upload should not make any requests" ); @@ -457,23 +522,18 @@ async fn test_update_with_retries() -> Result<(), Error> { } let send_data = send_data.freeze(); - let client = MockAzureClient::new(vec![ - TestRequest::put( - TEST_HASH, - TEST_SIZE, - TestResponse::error(StatusCode::InternalServerError), - ), - TestRequest::put(TEST_HASH, TEST_SIZE, TestResponse::ok()), - ]); + let mock = MockTransport::new(); + mock.push_upload(error_response(StatusCode::InternalServerError)); + mock.push_upload(created()); - let retry_config = nativelink_config::stores::Retry { + let retry = Retry { max_retries: 3, delay: 0.0, jitter: 0.0, ..Default::default() }; - let store = create_test_store(client.clone(), Some(retry_config), None)?; + let store = create_test_store(Arc::clone(&mock), Some(retry), None)?; let (mut tx, rx) = make_buf_channel_pair(); let update_fut = store.update( @@ -492,178 +552,50 @@ async fn test_update_with_retries() -> Result<(), Error> { update_result?; send_result?; - assert_eq!(client.request_count(), 2); + assert_eq!(mock.request_count(), 2); Ok(()) } #[nativelink_test] async fn test_multipart_upload_large_file() -> Result<(), Error> { - const MIN_BLOCK_SIZE: usize = 5 * 1024 * 1024; // 5MB + const MIN_BLOCK_SIZE: usize = 5 * 1024 * 1024; // 5 MiB DEFAULT_BLOCK_SIZE. const TOTAL_SIZE: usize = MIN_BLOCK_SIZE * 2 + 50; - const DIGEST_STR: &str = TEST_HASH; let mut send_data = Vec::with_capacity(TOTAL_SIZE); for i in 0..TOTAL_SIZE { send_data.push(u8::try_from((i * 3) % 256).unwrap()); } - // Generate and manually URL-encode Base64-encoded block IDs - let block_ids: Vec = (0..3) - .map(|i| { - let block_id = format!("{i:032}"); - let base64_encoded = encode(block_id); - base64_encoded - .replace('=', "%3D") - .replace('+', "%2B") - .replace('/', "%2F") - }) - .collect(); - - let client = MockAzureClient::new(vec![ - TestRequest::new( - "PUT", - format!( - "{TEST_CONTAINER}/{DIGEST_STR}-{TOTAL_SIZE}?blockid={}&comp=block", - block_ids[0] - ), - TestResponse::ok(), - ), - TestRequest::new( - "PUT", - format!( - "{TEST_CONTAINER}/{DIGEST_STR}-{TOTAL_SIZE}?blockid={}&comp=block", - block_ids[1] - ), - TestResponse::ok(), - ), - TestRequest::new( - "PUT", - format!( - "{TEST_CONTAINER}/{DIGEST_STR}-{TOTAL_SIZE}?blockid={}&comp=block", - block_ids[2] - ), - TestResponse::ok(), - ), - TestRequest::new( - "PUT", - format!("{TEST_CONTAINER}/{DIGEST_STR}-{TOTAL_SIZE}?comp=blocklist"), - TestResponse::ok(), - ), - ]); - - let store = create_test_store(client.clone(), None, None)?; - let digest = DigestInfo::try_new(DIGEST_STR, TOTAL_SIZE)?; + // No queued responses: the mock returns 201 for every staged block and the + // final commit. The 10 MiB payload splits into three 5-MiB-or-less blocks. + let mock = MockTransport::new(); + let store = create_test_store(Arc::clone(&mock), None, None)?; + let digest = DigestInfo::try_new(TEST_HASH, TOTAL_SIZE)?; let store_key: StoreKey = StoreKey::from(&digest); store.update_oneshot(store_key, send_data.into()).await?; - assert_eq!(client.request_count(), 4); - Ok(()) -} - -#[nativelink_test] -async fn test_get_part_zero_digest() -> Result<(), Error> { - let digest = DigestInfo::new(Sha256::new().finalize().into(), 0); - let client = MockAzureClient::new(vec![]); - let store = Arc::new(create_test_store(client.clone(), None, None)?); - let (mut writer, mut reader) = make_buf_channel_pair(); - - let (get_result, file_data) = tokio::join!( - store.get_part(digest, &mut writer, 0, None), - reader.consume(Some(1024)) - ); - - get_result?; - let file_data = file_data.err_tip(|| "Error reading bytes")?; - assert_eq!(file_data.len(), 0, "Expected empty file content"); - assert_eq!( - client.request_count(), - 0, - "Expected no requests for zero digest" - ); - Ok(()) -} -#[nativelink_test] -async fn test_has_with_results_zero_digests() -> Result<(), Error> { - let digest = DigestInfo::new(Sha256::new().finalize().into(), 0); - let store_key: StoreKey = StoreKey::from(&digest); - let keys = vec![store_key]; - let mut results = vec![None]; - - let client = MockAzureClient::new(vec![]); // Should make no requests - let store = create_test_store(client.clone(), None, None)?; - - store.has_with_results(&keys, &mut results).await?; - - assert_eq!(results, vec![Some(0)]); - assert_eq!( - client.request_count(), - 0, - "Expected no requests for zero digest" - ); - Ok(()) -} - -#[nativelink_test] -async fn test_has_with_expired_result() -> Result<(), Error> { - const CONTENT_SIZE: usize = 10; - use mock_instant::thread_local::MockClock; - - let client = MockAzureClient::new(vec![ - TestRequest::head( - TEST_HASH, - CONTENT_SIZE as u64, - TestResponse::ok().with_content_length(512), - ), - TestRequest::head( - TEST_HASH, - CONTENT_SIZE as u64, - TestResponse::ok().with_content_length(512), - ), - ]); - - let store = create_test_store( - client.clone(), - Some(nativelink_config::stores::Retry { - max_retries: 1, - delay: 0.0, - jitter: 0.0, - ..Default::default() - }), - Some(2 * 24 * 60 * 60), - )?; - - // Time starts at 1970-01-01 00:00:00 - let digest = DigestInfo::try_new(TEST_HASH, CONTENT_SIZE)?; - - // Check at 1 day (Not expired) - { - MockClock::advance(Duration::from_secs(24 * 60 * 60)); - let mut results = vec![None]; - store - .has_with_results(&[digest.into()], &mut results) - .await?; - assert_eq!( - results, - vec![Some(512)], - "Should find non-expired content after 1 day" - ); - } - - // Check at 3 days (expired) - { - MockClock::advance(Duration::from_secs(3 * 24 * 60 * 60)); - let mut results = vec![None]; - store - .has_with_results(&[digest.into()], &mut results) - .await?; - assert_eq!( - results, - vec![None], - "Should not find expired content after 3 days" + // 3 staged blocks + 1 committed block list. + assert_eq!(mock.request_count(), 4); + + // The store commits a block list of fixed-width, zero-padded block ids. Assert + // the committed XML carries exactly those ids, base64-encoded, in order. + let committed = mock + .committed_block_list() + .expect("commit_block_list must have been called"); + let committed = core::str::from_utf8(&committed).expect("committed block list must be utf-8"); + + let mut last_pos = 0; + for block_id in 0..3 { + let encoded = azure_core::base64::encode(format!("{block_id:032}").into_bytes()); + let pos = committed.find(&encoded).unwrap_or_else(|| { + panic!("block id {block_id} ({encoded}) missing from committed list: {committed}") + }); + assert!( + pos >= last_pos, + "block ids must be committed in ascending order" ); + last_pos = pos; } - - assert_eq!(client.request_count(), 2); Ok(()) } diff --git a/nativelink-store/tests/common_s3_utils_test.rs b/nativelink-store/tests/common_s3_utils_test.rs new file mode 100644 index 000000000..839520af8 --- /dev/null +++ b/nativelink-store/tests/common_s3_utils_test.rs @@ -0,0 +1,73 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Verifies that AWS credential discovery can use link-local HTTP endpoints +//! without allowing unencrypted HTTP for S3 requests. + +use aws_smithy_runtime_api::client::http::HttpConnector; +use aws_smithy_runtime_api::client::orchestrator::HttpRequest; +use nativelink_config::stores::CommonObjectSpec; +use nativelink_macro::nativelink_test; +use nativelink_store::common_s3_utils::TlsClient; +use nativelink_util::spawn; +use nativelink_util::task::JoinHandleDropGuard; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; +use tokio::net::TcpListener; + +async fn start_http_server() -> (String, JoinHandleDropGuard<()>) { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let address = listener.local_addr().unwrap(); + let server = spawn!("credential HTTP test server", async move { + let (mut socket, _) = listener.accept().await.unwrap(); + let mut request = [0; 1024]; + let _bytes_read = socket.read(&mut request).await.unwrap(); + socket + .write_all(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") + .await + .unwrap(); + }); + (format!("http://{address}/credentials"), server) +} + +#[nativelink_test] +async fn credential_client_allows_http() { + let common = CommonObjectSpec::default(); + assert!(!common.insecure_allow_http); + + let (credential_url, credential_server) = start_http_server().await; + let credential_result = TlsClient::new_for_credentials(&common) + .call(HttpRequest::get(credential_url).unwrap()) + .await; + assert!( + credential_result.is_ok(), + "credential client should allow HTTP: {credential_result:?}" + ); + credential_server.await.unwrap(); +} + +#[nativelink_test] +async fn s3_client_rejects_http_by_default() { + let common = CommonObjectSpec::default(); + assert!(!common.insecure_allow_http); + + let (s3_url, s3_server) = start_http_server().await; + let s3_result = TlsClient::new(&common) + .call(HttpRequest::get(s3_url).unwrap()) + .await; + drop(s3_server); + assert!( + s3_result.is_err(), + "S3 client should reject HTTP: {s3_result:?}" + ); +} diff --git a/nativelink-store/tests/compression_store_test.rs b/nativelink-store/tests/compression_store_test.rs index 3c57780fc..b95e55c77 100644 --- a/nativelink-store/tests/compression_store_test.rs +++ b/nativelink-store/tests/compression_store_test.rs @@ -15,26 +15,34 @@ use core::cmp; use core::pin::Pin; use core::str::from_utf8; +use core::sync::atomic::{AtomicUsize, Ordering}; use std::io::Cursor; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; +use async_trait::async_trait; use bytes::Bytes; use nativelink_config::stores::{CompressionSpec, MemorySpec, StoreSpec}; use nativelink_error::{Code, Error, ResultExt, make_err}; use nativelink_macro::nativelink_test; +use nativelink_metric::MetricsComponent; +use nativelink_store::cas_utils::ZERO_BYTE_DIGESTS; use nativelink_store::compression_store::{ CURRENT_STREAM_FORMAT_VERSION, CompressionStore, DEFAULT_BLOCK_SIZE, FOOTER_FRAME_TYPE, Footer, Lz4Config, SliceIndex, WincodeConfig, }; use nativelink_store::memory_store::MemoryStore; -use nativelink_util::buf_channel::make_buf_channel_pair; +use nativelink_util::buf_channel::{ + DropCloserReadHalf, DropCloserWriteHalf, make_buf_channel_pair, +}; use nativelink_util::common::DigestInfo; +use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::spawn; -use nativelink_util::store_trait::{Store, StoreLike, UploadSizeInfo}; +use nativelink_util::store_trait::{ + RemoveItemCallback, Store, StoreKey, StoreLike, UploadSizeInfo, +}; use pretty_assertions::assert_eq; use rand::rngs::SmallRng; use rand::{Rng, SeedableRng}; -use sha2::{Digest, Sha256}; use tokio::io::AsyncReadExt; /// Utility function that will build a Footer object from the input. @@ -67,6 +75,105 @@ const VALID_HASH: &str = "0123456789abcdef00000000000000000001000000000000012345 const DUMMY_DATA_SIZE: usize = 100; // Some dummy size to populate DigestInfo with. const MEGABYTE_SZ: usize = 1024 * 1024; +mod recording_store { + use nativelink_util::store_trait::StoreDriver; + + use super::*; + + #[derive(MetricsComponent)] + pub(super) struct RecordingStore { + pub(super) has_call_count: AtomicUsize, + pub(super) has_key_count: AtomicUsize, + pub(super) has_keys: Mutex>>, + pub(super) update_count: AtomicUsize, + } + + #[async_trait] + impl StoreDriver for RecordingStore { + async fn post_init(self: Arc) -> Result<(), Error> { + Ok(()) + } + + async fn has_with_results( + self: Pin<&Self>, + keys: &[StoreKey<'_>], + results: &mut [Option], + ) -> Result<(), Error> { + self.has_call_count.fetch_add(1, Ordering::Relaxed); + self.has_key_count.fetch_add(keys.len(), Ordering::Relaxed); + *self.has_keys.lock().unwrap() = + keys.iter().map(|key| key.borrow().into_owned()).collect(); + for (size, result) in (100..).zip(results.iter_mut()) { + *result = Some(size); + } + Ok(()) + } + + async fn update( + self: Pin<&Self>, + _key: StoreKey<'_>, + _reader: DropCloserReadHalf, + _size_info: UploadSizeInfo, + ) -> Result { + self.update_count.fetch_add(1, Ordering::Relaxed); + Ok(0) + } + + async fn get_part( + self: Pin<&Self>, + _key: StoreKey<'_>, + _writer: &mut DropCloserWriteHalf, + _offset: u64, + _length: Option, + ) -> Result<(), Error> { + Err(make_err!(Code::NotFound, "Not found")) + } + + fn inner_store(&self, _key: Option) -> &dyn StoreDriver { + self + } + + fn as_any(&self) -> &(dyn core::any::Any + Sync + Send + 'static) { + self + } + + fn as_any_arc(self: Arc) -> Arc { + self + } + + fn register_remove_callback( + self: Arc, + _callback: Arc, + ) -> Result<(), Error> { + Ok(()) + } + } + + default_health_status_indicator!(RecordingStore); +} + +use recording_store::RecordingStore; + +fn make_recording_compression_store() -> Result<(Arc, Arc), Error> +{ + let inner_store = Arc::new(RecordingStore { + has_call_count: AtomicUsize::new(0), + has_key_count: AtomicUsize::new(0), + has_keys: Mutex::new(Vec::new()), + update_count: AtomicUsize::new(0), + }); + let store = CompressionStore::new( + &CompressionSpec { + backend: StoreSpec::Memory(MemorySpec::default()), + compression_algorithm: nativelink_config::stores::CompressionAlgorithm::Lz4( + nativelink_config::stores::Lz4Config::default(), + ), + }, + Store::new(inner_store.clone()), + )?; + Ok((store, inner_store)) +} + #[nativelink_test] async fn simple_smoke_test() -> Result<(), Error> { const RAW_INPUT: &str = "123"; @@ -469,7 +576,7 @@ async fn check_footer_test() -> Result<(), Error> { async fn get_part_is_zero_digest() -> Result<(), Error> { const BLOCK_SIZE: u32 = 32 * 1024; - let digest = DigestInfo::new(Sha256::new().finalize().into(), 0); + let digest = ZERO_BYTE_DIGESTS[0]; let inner_store = MemoryStore::new(&MemorySpec::default()); let store_owned = CompressionStore::new( @@ -510,6 +617,109 @@ async fn get_part_is_zero_digest() -> Result<(), Error> { Ok(()) } +#[nativelink_test] +async fn update_zero_digest_skips_inner_store() -> Result<(), Error> { + let (store, inner_store) = make_recording_compression_store()?; + for digest in ZERO_BYTE_DIGESTS { + store.update_oneshot(digest, Bytes::new()).await?; + } + assert_eq!(inner_store.update_count.load(Ordering::Relaxed), 0); + Ok(()) +} + +#[nativelink_test] +async fn update_zero_digest_rejects_nonempty_data() -> Result<(), Error> { + let (store, inner_store) = make_recording_compression_store()?; + for digest in ZERO_BYTE_DIGESTS { + let err = store + .update_oneshot(digest, Bytes::from_static(b"not empty")) + .await + .expect_err("Expected nonempty data for a zero digest to fail"); + assert!( + err.to_string().contains("Zero byte hash not empty"), + "Unexpected error: {err}" + ); + } + assert_eq!(inner_store.update_count.load(Ordering::Relaxed), 0); + Ok(()) +} + +#[nativelink_test] +async fn has_zero_digests_skips_inner_store() -> Result<(), Error> { + let (store, inner_store) = make_recording_compression_store()?; + let keys = ZERO_BYTE_DIGESTS.map(StoreKey::from); + let mut results = [None; ZERO_BYTE_DIGESTS.len()]; + + store.has_with_results(&keys, &mut results).await?; + let expected_keys: &[StoreKey<'static>] = &[]; + assert_eq!( + ( + results, + inner_store.has_call_count.load(Ordering::Relaxed), + inner_store.has_key_count.load(Ordering::Relaxed), + inner_store.has_keys.lock().unwrap().as_slice(), + ), + ([Some(0); ZERO_BYTE_DIGESTS.len()], 0, 0, expected_keys,) + ); + Ok(()) +} + +#[nativelink_test] +async fn has_mixed_digests_preserves_result_order() -> Result<(), Error> { + let (store, inner_store) = make_recording_compression_store()?; + let keys = [ + StoreKey::from(ZERO_BYTE_DIGESTS[0]), + StoreKey::new_str("first"), + StoreKey::from(ZERO_BYTE_DIGESTS[1]), + StoreKey::new_str("second"), + ]; + let mut results = [None; 4]; + + store.has_with_results(&keys, &mut results).await?; + let expected_keys = [ + StoreKey::new_str("first").into_owned(), + StoreKey::new_str("second").into_owned(), + ]; + assert_eq!( + ( + results, + inner_store.has_call_count.load(Ordering::Relaxed), + inner_store.has_key_count.load(Ordering::Relaxed), + inner_store.has_keys.lock().unwrap().as_slice(), + ), + ( + [Some(0), Some(100), Some(0), Some(101)], + 1, + 2, + expected_keys.as_slice(), + ) + ); + Ok(()) +} + +#[nativelink_test] +async fn has_nonzero_digests_delegates_single_batch() -> Result<(), Error> { + let (store, inner_store) = make_recording_compression_store()?; + let keys = [StoreKey::new_str("first"), StoreKey::new_str("second")]; + let mut results = [None; 2]; + + store.has_with_results(&keys, &mut results).await?; + let expected_keys = [ + StoreKey::new_str("first").into_owned(), + StoreKey::new_str("second").into_owned(), + ]; + assert_eq!( + ( + results, + inner_store.has_call_count.load(Ordering::Relaxed), + inner_store.has_key_count.load(Ordering::Relaxed), + inner_store.has_keys.lock().unwrap().as_slice(), + ), + ([Some(100), Some(101)], 1, 2, expected_keys.as_slice()) + ); + Ok(()) +} + // Regression test for the bug where start_pos > end_pos in the slice operation #[nativelink_test] async fn regression_test_range_start_not_greater_than_end() -> Result<(), Error> { diff --git a/nativelink-store/tests/fast_slow_store_test.rs b/nativelink-store/tests/fast_slow_store_test.rs index 769c489e6..b6ee7ee5a 100644 --- a/nativelink-store/tests/fast_slow_store_test.rs +++ b/nativelink-store/tests/fast_slow_store_test.rs @@ -33,7 +33,7 @@ use nativelink_util::buf_channel::{ use nativelink_util::common::DigestInfo; use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use pretty_assertions::assert_eq; use rand::rngs::SmallRng; @@ -323,7 +323,7 @@ async fn drop_on_eof_completes_store_futures() -> Result<(), Error> { fn register_remove_callback( self: Arc, - _callback: Arc, + _callback: RemoveCallback, ) -> Result<(), Error> { Ok(()) } @@ -654,7 +654,7 @@ fn make_stores_with_lazy_slow() -> (Store, Store, Store) { fn register_remove_callback( self: Arc, - _callback: Arc, + _callback: RemoveCallback, ) -> Result<(), Error> { Ok(()) } @@ -794,10 +794,7 @@ impl StoreDriver for InstrumentedSlowStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { Ok(()) } } @@ -1050,7 +1047,7 @@ async fn has_sees_in_flight_slow_writes() -> Result<(), Error> { fn register_remove_callback( self: Arc, - _callback: Arc, + _callback: RemoveCallback, ) -> Result<(), Error> { Ok(()) } @@ -1210,7 +1207,7 @@ async fn has_does_not_consult_fast_store_when_slow_store_hits() -> Result<(), Er fn register_remove_callback( self: Arc, - _callback: Arc, + _callback: RemoveCallback, ) -> Result<(), Error> { Ok(()) } @@ -1316,10 +1313,7 @@ impl StoreDriver for GatedSlowStore2 { fn as_any_arc(self: Arc) -> Arc { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { Ok(()) } } @@ -1476,10 +1470,7 @@ impl StoreDriver for MapBackedSlow { fn as_any_arc(self: Arc) -> Arc { self } - fn register_remove_callback( - self: Arc, - _cb: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _cb: RemoveCallback) -> Result<(), Error> { Ok(()) } } @@ -1658,10 +1649,7 @@ impl StoreDriver for CountingSlowStore { fn as_any_arc(self: Arc) -> Arc { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { Ok(()) } } @@ -1922,10 +1910,7 @@ impl StoreDriver for StaleFastStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { Ok(()) } } diff --git a/nativelink-store/tests/filesystem_store_test.rs b/nativelink-store/tests/filesystem_store_test.rs index 0e59d883e..17da82e59 100644 --- a/nativelink-store/tests/filesystem_store_test.rs +++ b/nativelink-store/tests/filesystem_store_test.rs @@ -51,7 +51,7 @@ use tokio::sync::{Barrier, Semaphore}; use tokio::time::sleep; use tokio_stream::StreamExt; use tokio_stream::wrappers::ReadDirStream; -use tracing::{Instrument, debug}; +use tracing::{Instrument, debug, info}; const VALID_HASH: &str = "0123456789abcdef000000000000000000010000000000000123456789abcdef"; @@ -271,6 +271,33 @@ const VALUE1: &str = "0123456789"; const VALUE2: &str = "9876543210"; const STRING_NAME: &str = "String_Filename"; +#[nativelink_test] +async fn evict_page_cache_defaults_off_and_round_trips_when_on() -> Result<(), Error> { + assert!( + !FilesystemSpec::default().evict_page_cache, + "evict_page_cache should default to off" + ); + + let digest = DigestInfo::try_new(HASH1, VALUE1.len())?; + let store = Store::new( + FilesystemStore::::new(&FilesystemSpec { + content_path: make_temp_path("content_path"), + temp_path: make_temp_path("temp_path"), + eviction_policy: None, + block_size: 1, + evict_page_cache: true, + ..Default::default() + }) + .await?, + ); + store.update_oneshot(digest, VALUE1.into()).await?; + let content = store + .get_part_unchunked(StoreKey::Digest(digest), 0, None) + .await?; + assert_eq!(content, VALUE1.as_bytes()); + Ok(()) +} + #[nativelink_test] async fn valid_results_after_shutdown_test() -> Result<(), Error> { let digest = DigestInfo::try_new(HASH1, VALUE1.len())?; @@ -1493,7 +1520,7 @@ async fn add_too_early_files() -> Result<(), Error> { fs_set_times::set_atime( &demo_file_path, SystemTime::now() - .checked_add(Duration::from_secs(60)) + .checked_add(Duration::from_mins(1)) .unwrap() .into(), )?; @@ -1663,6 +1690,116 @@ async fn executable_hardlink_source_created_once_and_readonly() -> Result<(), Er Ok(()) } +/// A store whose `.exec` directory cannot be cleared must still start and +/// serve ordinary CAS reads. It must not, however, trust an executable variant +/// left behind by an earlier process: that file may be stale or torn after an +/// unclean shutdown, so the executable hardlink fast path stays disabled until +/// the directory can be wiped on a later writable startup. +#[cfg(target_family = "unix")] +#[nativelink_test] +async fn read_only_executable_dir_preserves_cas_reads_without_reusing_variants() -> Result<(), Error> +{ + use std::os::unix::fs::PermissionsExt; + + struct RestoreWritable(String); + + impl Drop for RestoreWritable { + fn drop(&mut self) { + use std::os::unix::fs::PermissionsExt; + + std::fs::set_permissions(&self.0, std::fs::Permissions::from_mode(0o755)) + .expect("restore executable digest directory permissions"); + } + } + + let content_path = make_temp_path("content_path_read_only_exec"); + let temp_path = make_temp_path("temp_path_read_only_exec"); + let digest = DigestInfo::try_new(HASH1, VALUE1.len())?; + let spec = FilesystemSpec { + content_path: content_path.clone(), + temp_path, + ..Default::default() + }; + + { + let store = FilesystemStore::::new(&spec).await?; + store.update_oneshot(digest, VALUE1.into()).await?; + store.get_executable_hardlink_source(&digest).await?; + } + + let executable_digest_dir = format!("{content_path}.exec/{DIGEST_FOLDER}"); + fs::set_permissions( + &executable_digest_dir, + std::fs::Permissions::from_mode(0o555), + ) + .await?; + let _restore_permissions = RestoreWritable(executable_digest_dir); + + let store = FilesystemStore::::new(&spec).await?; + assert_eq!( + store.get_part_unchunked(digest, 0, None).await?, + VALUE1.as_bytes(), + "read-only executable cleanup must not prevent ordinary CAS reads" + ); + let err = store + .get_executable_hardlink_source(&digest) + .await + .expect_err("a surviving executable variant must not be trusted"); + assert_eq!(err.code, Code::FailedPrecondition); + + Ok(()) +} + +/// Regression test for #2474: the `.exec` variant directory was never +/// registered in `evicting_map`, so it was invisible to `max_bytes` and only +/// ever cleared by the startup `remove_dir_all` — growing without bound at +/// runtime. Evicting a digest from the primary CAS must also delete its +/// `.exec` sibling, bounding total `.exec` disk use to the primary store's +/// own eviction policy instead of letting it grow forever. +#[cfg(target_family = "unix")] +#[nativelink_test] +async fn evicting_digest_deletes_its_executable_variant() -> Result<(), Error> { + let content_path = make_temp_path("content_path"); + let temp_path = make_temp_path("temp_path"); + let digest1 = DigestInfo::try_new(HASH1, VALUE1.len())?; + let digest2 = DigestInfo::try_new(HASH2, VALUE2.len())?; + + let store = Box::pin( + FilesystemStore::::new(&FilesystemSpec { + content_path: content_path.clone(), + temp_path: temp_path.clone(), + eviction_policy: Some(EvictionPolicy { + max_count: 1, + ..Default::default() + }), + ..Default::default() + }) + .await?, + ); + store.update_oneshot(digest1, VALUE1.into()).await?; + + let variant_path = OsString::from(format!("{content_path}.exec/{DIGEST_FOLDER}/{digest1}")); + store.get_executable_hardlink_source(&digest1).await?; + fs::metadata(&variant_path) + .await + .err_tip(|| "Executable variant should exist right after creation")?; + + // max_count: 1 means inserting a second digest evicts the first from the + // primary evicting_map, which must also delete digest1's `.exec` sibling. + store.update_oneshot(digest2, VALUE2.into()).await?; + + let err = fs::metadata(&variant_path) + .await + .expect_err("Executable variant must be deleted when its digest is evicted"); + assert_eq!( + err.code, + Code::NotFound, + "Expected the executable variant to be gone, got: {err:?}" + ); + + Ok(()) +} + /// This test simulates a full disk without needing one. It writes past the `RLIMIT_FSIZE` /// cap, thus failing with `EFBIG`, which tokio defers exactly like `ENOSPC`. The /// [`SIGXFSZ`](`libc::SIGXFSZ`) signal must be ignored or the kernel will kill the process @@ -1765,18 +1902,23 @@ async fn detect_duplicate_upload() -> Result<(), Error> { let key = &StoreKey::Digest(digest); let temp_key = make_temp_key(key); - let (mut entry, mut temp_file, _temp_full_path) = store.make_temp_file(temp_key).await?; + let (mut entry, mut temp_file, temp_full_path) = store.make_temp_file(temp_key).await?; + info!(?temp_full_path, "Temp full path"); let mut data = Bytes::from_static(VALUE1.as_bytes()); temp_file.write_all_buf(&mut data).await?; + temp_file.flush().await?; *entry.data_size_mut() = 10; + let arc_entry = Arc::new(entry); assert!( - check_duplicate_files(&store.get_evicting_map(), key, &Arc::new(entry)).await?, + check_duplicate_files(&store.get_evicting_map(), key, &arc_entry).await?, "Expected duplicate" ); assert!(logs_contain( "Identical files, so don't need to edit, skipping emplace" )); + // Keep it alive until here to avoid early drop and delete, which breaks the test + drop(arc_entry); Ok(()) } @@ -1789,6 +1931,7 @@ async fn detect_same_key_different_contents() -> Result<(), Error> { let (mut entry, mut temp_file, _temp_full_path) = store.make_temp_file(temp_key).await?; let mut data = Bytes::from_static(VALUE2.as_bytes()); temp_file.write_all_buf(&mut data).await?; + temp_file.flush().await?; *entry.data_size_mut() = 10; assert!( @@ -1926,3 +2069,74 @@ async fn unref_does_not_orphan_content_file_when_temp_dir_missing() -> Result<() Ok(()) } + +// Exercises the macOS flush coalescer's round machinery under a burst of +// concurrent uploads (on other platforms this is a plain concurrency smoke +// test). Two hundred small, independently durable blobs are used because each +// upload would otherwise issue its own multi-millisecond `F_FULLFSYNC` on +// macOS. The data volume is deliberately small so file I/O does not hide the +// synchronization behavior: every blob must complete and survive restart, +// while the device-wide barrier count must remain far below the blob count. +#[nativelink_test(flavor = "multi_thread", worker_threads = 4)] +async fn concurrent_upload_burst_round_trip_test() -> Result<(), Error> { + const NUM_BLOBS: u64 = 200; + let content_path = make_temp_path("content_path_burst"); + let temp_path = make_temp_path("temp_path_burst"); + let spec = FilesystemSpec { + content_path: content_path.clone(), + temp_path: temp_path.clone(), + eviction_policy: None, + block_size: 1, + ..Default::default() + }; + let make_digest = |i: u64| { + let mut hash = [0u8; 32]; + hash[0] = 0xbb; + hash[1..9].copy_from_slice(&i.to_le_bytes()); + DigestInfo::new(hash, 25) + }; + { + let filesystem_store = FilesystemStore::::new(&spec).await?; + let store = Store::new(filesystem_store.clone()); + let mut handles = Vec::new(); + for i in 0..NUM_BLOBS { + let store = store.clone(); + handles.push(tokio::spawn(async move { + let content = format!("burst-content-{i:011}"); + store + .update_oneshot(make_digest(i), content.into_bytes().into()) + .await + })); + } + for handle in handles { + handle.await.expect("upload task panicked")?; + } + #[cfg(target_os = "macos")] + { + let full_flush_count = filesystem_store + .full_flush_count_for_test() + .expect("writable test store must have a flush coalescer"); + assert!( + full_flush_count > 0 && full_flush_count < NUM_BLOBS / 2, + "{NUM_BLOBS} concurrent uploads should share device-wide barriers; observed {full_flush_count} F_FULLFSYNC rounds" + ); + } + for i in 0..NUM_BLOBS { + assert_eq!( + store.get_part_unchunked(make_digest(i), 0, None).await?, + format!("burst-content-{i:011}").as_bytes(), + "round trip failed for blob {i}" + ); + } + } + // A fresh store over the same paths must find every published blob. + let store = Store::new(FilesystemStore::::new(&spec).await?); + for i in 0..NUM_BLOBS { + assert_eq!( + store.has(make_digest(i)).await?, + Some(25), + "blob {i} missing after restart" + ); + } + Ok(()) +} diff --git a/nativelink-store/tests/gcs_store_test.rs b/nativelink-store/tests/gcs_store_test.rs index 34f9cba4d..93fae5c6f 100644 --- a/nativelink-store/tests/gcs_store_test.rs +++ b/nativelink-store/tests/gcs_store_test.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use bytes::{BufMut, Bytes, BytesMut}; use mock_instant::thread_local::MockClock; -use nativelink_config::stores::{CommonObjectSpec, ExperimentalGcsSpec}; +use nativelink_config::stores::{CommonObjectSpec, ErrorCode, ExperimentalGcsSpec, Retry}; use nativelink_error::{Code, Error, make_err}; use nativelink_macro::nativelink_test; use nativelink_store::cas_utils::ZERO_BYTE_DIGESTS; @@ -181,6 +181,90 @@ async fn get_part_handles_not_found_error() -> Result<(), Error> { Ok(()) } +#[nativelink_test] +async fn get_part_not_found_not_retried_by_default() -> Result<(), Error> { + // Create mock GCS operations without adding any object, so reads + // yield NotFound. + let mock_ops = Arc::new(MockGcsOperations::new()); + let store = create_test_store_with_retry( + mock_ops.clone(), + Retry { + max_retries: 2, + delay: 0.001, + jitter: 0.0, + ..Default::default() + }, + ) + .await?; + + let digest = DigestInfo::try_new(VALID_HASH1, 100)?; + let store_key: StoreKey = to_store_key(digest); + let (mut tx, _rx) = make_buf_channel_pair(); + + let store_clone = store.clone(); + let get_part_fut = nativelink_util::spawn!("get_part_task", async move { + store_clone.get_part(store_key, &mut tx, 0, None).await + }); + + let err = get_part_fut.await?.unwrap_err(); + assert_eq!(err.code, Code::NotFound, "Expected NotFound error"); + + // Even with a retry budget configured, NotFound must not consume it + // unless explicitly opted in via `retry_on_errors`. + let call_counts = mock_ops.get_call_counts(); + assert_eq!( + call_counts.read_calls.load(Ordering::Relaxed), + 1, + "read_object_content should not be retried on NotFound by default" + ); + + Ok(()) +} + +#[nativelink_test] +async fn get_part_retries_not_found_when_opted_in() -> Result<(), Error> { + // Create mock GCS operations without adding any object, so reads + // yield NotFound. + let mock_ops = Arc::new(MockGcsOperations::new()); + let store = create_test_store_with_retry( + mock_ops.clone(), + Retry { + max_retries: 2, + delay: 0.001, + jitter: 0.0, + retry_on_errors: Some(vec![ErrorCode::NotFound]), + }, + ) + .await?; + + let digest = DigestInfo::try_new(VALID_HASH1, 100)?; + let store_key: StoreKey = to_store_key(digest); + let (mut tx, _rx) = make_buf_channel_pair(); + + let store_clone = store.clone(); + let get_part_fut = nativelink_util::spawn!("get_part_task", async move { + store_clone.get_part(store_key, &mut tx, 0, None).await + }); + + let err = get_part_fut.await?.unwrap_err(); + assert_eq!( + err.code, + Code::NotFound, + "Expected NotFound error after retries are exhausted" + ); + + // With NotFound in `retry_on_errors`, the read should be attempted + // once plus `max_retries` more times before giving up. + let call_counts = mock_ops.get_call_counts(); + assert_eq!( + call_counts.read_calls.load(Ordering::Relaxed), + 3, + "read_object_content should be retried on NotFound when opted in" + ); + + Ok(()) +} + #[nativelink_test] async fn has_with_results_test() -> Result<(), Error> { // Create mock GCS operations @@ -528,9 +612,7 @@ async fn test_expired_object() -> Result<(), Error> { .await; // Mock the now function to return a time before expiration - MockClock::set_time(Duration::from_secs( - base_timestamp as u64 + expiration_seconds as u64 - 1, - )); + MockClock::set_time(Duration::from_secs(base_timestamp + expiration_seconds - 1)); // Check that the object exists (it's not expired yet) let result = store.has(store_key.clone()).await?; @@ -541,9 +623,7 @@ async fn test_expired_object() -> Result<(), Error> { ); // Mock the now function to return a time after expiration - MockClock::set_time(Duration::from_secs( - base_timestamp as u64 + expiration_seconds as u64 + 1, - )); + MockClock::set_time(Duration::from_secs(base_timestamp + expiration_seconds + 1)); // Object should now be considered expired let result = store.has(store_key).await?; @@ -648,7 +728,7 @@ async fn test_null_object_metadata() -> Result<(), Error> { let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap_or_default() - .as_secs() as i64; + .as_secs(); let metadata = nativelink_store::gcs_client::types::GcsObject { name: object_path.path.clone(), @@ -705,10 +785,30 @@ async fn create_test_store( ) } +// Helper function to create a test GCS store with a custom retry config +async fn create_test_store_with_retry( + ops: Arc, + retry: Retry, +) -> Result MockInstantWrapped>>, Error> { + GcsStore::new_with_ops( + &ExperimentalGcsSpec { + bucket: BUCKET_NAME.to_string(), + common: CommonObjectSpec { + key_prefix: Some(KEY_PREFIX.to_string()), + retry, + ..Default::default() + }, + ..Default::default() + }, + ops, + MockInstantWrapped::default, + ) +} + // Helper function to create a test GCS store with expiration async fn create_test_store_with_expiration( ops: Arc, - expiration_seconds: i64, + expiration_seconds: u64, ) -> Result MockInstantWrapped>>, Error> { GcsStore::new_with_ops( &ExperimentalGcsSpec { @@ -771,3 +871,148 @@ async fn check_health_failed_on_object_exists_error() -> Result<(), Error> { other => panic!("expected HealthStatus::Failed, got {other:?}"), } } + +#[nativelink_test] +async fn get_part_ignores_empty_stream_chunks() -> Result<(), Error> { + use futures::stream::{self, Stream, StreamExt}; + use nativelink_store::gcs_client::types::GcsObject; + use nativelink_util::buf_channel::DropCloserReadHalf; + + /// Wraps `MockGcsOperations`, re-chunking every content read so the + /// stream interleaves zero-length chunks the way an HTTP/2 peer that + /// emits empty DATA frames does. + #[derive(Debug)] + struct EmptyChunkOps(Arc); + + impl GcsOperations for EmptyChunkOps { + async fn read_object_metadata( + &self, + object: &ObjectPath, + ) -> Result, Error> { + self.0.read_object_metadata(object).await + } + + async fn read_object_content( + &self, + object_path: &ObjectPath, + start: u64, + end: Option, + ) -> Result> + Send + Unpin>, Error> { + let mut inner = self.0.read_object_content(object_path, start, end).await?; + let mut content = BytesMut::new(); + while let Some(chunk) = inner.next().await { + content.put(chunk?); + } + let content = content.freeze(); + let mid = content.len() / 2; + Ok(Box::new(stream::iter(vec![ + Ok(Bytes::new()), + Ok(content.slice(..mid)), + Ok(Bytes::new()), + Ok(content.slice(mid..)), + Ok(Bytes::new()), + ]))) + } + + async fn write_object( + &self, + object_path: &ObjectPath, + content: Vec, + ) -> Result<(), Error> { + self.0.write_object(object_path, content).await + } + + async fn start_resumable_write(&self, object_path: &ObjectPath) -> Result { + self.0.start_resumable_write(object_path).await + } + + async fn upload_chunk( + &self, + upload_url: &str, + object_path: &ObjectPath, + data: Bytes, + offset: u64, + end_offset: u64, + total_size: Option, + ) -> Result<(), Error> { + self.0 + .upload_chunk( + upload_url, + object_path, + data, + offset, + end_offset, + total_size, + ) + .await + } + + async fn upload_from_reader( + &self, + object_path: &ObjectPath, + reader: &mut DropCloserReadHalf, + upload_id: &str, + max_size: u64, + ) -> Result<(), Error> { + self.0 + .upload_from_reader(object_path, reader, upload_id, max_size) + .await + } + + async fn object_exists(&self, object_path: &ObjectPath) -> Result { + self.0.object_exists(object_path).await + } + } + + let mock_ops = Arc::new(MockGcsOperations::new()); + let digest = DigestInfo::try_new(VALID_HASH1, 11)?; // "hello world" length + let store_key: StoreKey = to_store_key(digest); + let object_path = create_object_path(&store_key); + mock_ops + .add_object(&object_path, b"hello world".to_vec()) + .await; + + let store = GcsStore::new_with_ops( + &ExperimentalGcsSpec { + bucket: BUCKET_NAME.to_string(), + common: CommonObjectSpec { + key_prefix: Some(KEY_PREFIX.to_string()), + ..Default::default() + }, + ..Default::default() + }, + Arc::new(EmptyChunkOps(mock_ops)), + MockInstantWrapped::default, + )?; + + let (mut tx, mut rx) = make_buf_channel_pair(); + let store_clone = store.clone(); + let store_key_clone = store_key.clone(); + + let handle = nativelink_util::spawn!("get_part_task", async move { + store_clone + .get_part(store_key_clone, &mut tx, 0, None) + .await + }); + + let received_data = + match tokio::time::timeout(Duration::from_secs(5), rx.consume(Some(100))).await { + Ok(result) => result?, + Err(_) => { + return Err(make_err!( + Code::DeadlineExceeded, + "Timeout waiting for data" + )); + } + }; + + assert_eq!( + received_data.as_ref(), + b"hello world", + "Received data should match original despite empty stream chunks" + ); + + handle.await??; + + Ok(()) +} diff --git a/nativelink-store/tests/grpc_read_batching_test.rs b/nativelink-store/tests/grpc_read_batching_test.rs new file mode 100644 index 000000000..7931e9abc --- /dev/null +++ b/nativelink-store/tests/grpc_read_batching_test.rs @@ -0,0 +1,574 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context as TaskContext, Waker}; +use std::collections::{HashMap, HashSet}; +use std::sync::Arc; + +use async_lock::Mutex; +use bytes::Bytes; +use futures::Stream; +use nativelink_config::stores::{GrpcEndpoint, GrpcReadBatchingConfig, GrpcSpec, Retry, StoreType}; +use nativelink_error::{Code, Error}; +use nativelink_macro::nativelink_test; +use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_storage_server::{ + ContentAddressableStorage, ContentAddressableStorageServer, +}; +use nativelink_proto::build::bazel::remote::execution::v2::{ + BatchReadBlobsRequest, BatchReadBlobsResponse, BatchUpdateBlobsRequest, + BatchUpdateBlobsResponse, FindMissingBlobsRequest, FindMissingBlobsResponse, GetTreeRequest, + GetTreeResponse, SpliceBlobRequest, SpliceBlobResponse, SplitBlobRequest, SplitBlobResponse, + batch_read_blobs_response, +}; +use nativelink_proto::google::bytestream::byte_stream_server::{ByteStream, ByteStreamServer}; +use nativelink_proto::google::bytestream::{ + QueryWriteStatusRequest, QueryWriteStatusResponse, ReadRequest, ReadResponse, WriteRequest, + WriteResponse, +}; +use nativelink_proto::google::rpc::Status as RpcStatus; +use nativelink_store::grpc_store::GrpcStore; +use nativelink_util::background_spawn; +use nativelink_util::common::DigestInfo; +use nativelink_util::store_trait::StoreLike; +use tonic::transport::Server; +use tonic::transport::server::TcpIncoming; +use tonic::{Request, Response, Status, Streaming}; + +/// A fake CAS server that serves seeded blobs from `BatchReadBlobs` and +/// records every `BatchReadBlobs` request it receives. Digests listed in +/// `not_found_hashes` are reported as `NOT_FOUND` in the per-blob status. +#[derive(Debug, Clone)] +struct FakeCasServer { + blobs: Arc>>, + not_found_hashes: Arc>>, + batch_read_requests: Arc>>, +} + +impl FakeCasServer { + fn new() -> Self { + Self { + blobs: Arc::new(Mutex::new(HashMap::new())), + not_found_hashes: Arc::new(Mutex::new(vec![])), + batch_read_requests: Arc::new(Mutex::new(vec![])), + } + } +} + +type GetTreeStream = Pin> + Send + 'static>>; + +#[tonic::async_trait] +impl ContentAddressableStorage for FakeCasServer { + type GetTreeStream = GetTreeStream; + + #[allow(clippy::unimplemented)] + async fn find_missing_blobs( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + #[allow(clippy::unimplemented)] + async fn batch_update_blobs( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + async fn batch_read_blobs( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + self.batch_read_requests.lock().await.push(request.clone()); + + let blobs = self.blobs.lock().await; + let not_found_hashes = self.not_found_hashes.lock().await; + let mut responses = Vec::with_capacity(request.digests.len()); + // Real servers may dedupe duplicate digests in one request; mimic + // that by returning exactly one entry per unique digest. + let mut seen_hashes = HashSet::new(); + for digest in request.digests { + if !seen_hashes.insert(digest.hash.clone()) { + continue; + } + let (data, status) = if not_found_hashes.contains(&digest.hash) { + ( + Bytes::new(), + RpcStatus { + code: Code::NotFound as i32, + message: format!("Blob {} not found", digest.hash), + details: vec![], + }, + ) + } else if let Some(data) = blobs.get(&digest.hash) { + ( + data.clone(), + RpcStatus { + code: Code::Ok as i32, + message: String::new(), + details: vec![], + }, + ) + } else { + return Err(Status::invalid_argument(format!( + "Blob {} was never seeded in FakeCasServer", + digest.hash + ))); + }; + responses.push(batch_read_blobs_response::Response { + digest: Some(digest), + data, + compressor: 0, + status: Some(status), + }); + } + Ok(Response::new(BatchReadBlobsResponse { responses })) + } + + #[allow(clippy::unimplemented)] + async fn get_tree( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + #[allow(clippy::unimplemented)] + async fn split_blob( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + #[allow(clippy::unimplemented)] + async fn splice_blob( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } +} + +type ReadStream = Pin> + Send + 'static>>; + +/// A fake `ByteStream` server that serves the same seeded blobs as +/// [`FakeCasServer`] and records every `Read` request it receives. +#[derive(Debug, Clone)] +struct FakeByteStreamServer { + blobs: Arc>>, + read_requests: Arc>>, +} + +impl FakeByteStreamServer { + fn new(blobs: Arc>>) -> Self { + Self { + blobs, + read_requests: Arc::new(Mutex::new(vec![])), + } + } +} + +#[tonic::async_trait] +impl ByteStream for FakeByteStreamServer { + type ReadStream = ReadStream; + + async fn read( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + self.read_requests.lock().await.push(request.clone()); + + // Resource names look like `{instance}/blobs/{fn}/{hash}/{size}`. + let mut components = request.resource_name.rsplit('/'); + let _size = components.next(); + let hash = components.next().unwrap_or_default().to_string(); + let data = self + .blobs + .lock() + .await + .get(&hash) + .cloned() + .ok_or_else(|| Status::not_found(format!("Blob {hash} not seeded")))?; + let offset = usize::try_from(request.read_offset) + .map_err(|_| Status::invalid_argument("Bad read_offset"))?; + if offset > data.len() { + return Err(Status::out_of_range("read_offset past end of blob")); + } + let stream: Self::ReadStream = Box::pin(futures::stream::iter(vec![Ok(ReadResponse { + data: data.slice(offset..), + })])); + Ok(Response::new(stream)) + } + + #[allow(clippy::unimplemented)] + async fn write( + &self, + _grpc_request: Request>, + ) -> Result, Status> { + unimplemented!(); + } + + #[allow(clippy::unimplemented)] + async fn query_write_status( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } +} + +struct TestFixture { + cas_server: FakeCasServer, + bytestream_server: FakeByteStreamServer, + store: Arc, +} + +async fn make_fixture(read_batching: Option) -> Result { + let cas_server = FakeCasServer::new(); + let bytestream_server = FakeByteStreamServer::new(cas_server.blobs.clone()); + let listener = TcpIncoming::bind("127.0.0.1:0".parse().unwrap()).unwrap(); + let port = listener.local_addr().unwrap().port(); + + let cas_service = ContentAddressableStorageServer::new(cas_server.clone()); + let bytestream_service = ByteStreamServer::new(bytestream_server.clone()); + background_spawn!("grpc_read_batching_test_server", async move { + Server::builder() + .add_service(cas_service) + .add_service(bytestream_service) + .serve_with_incoming(listener) + .await + .unwrap(); + }); + + let spec = GrpcSpec { + instance_name: String::new(), + endpoints: vec![GrpcEndpoint { + address: format!("http://localhost:{port}"), + tls_config: None, + concurrency_limit: None, + connect_timeout_s: 0, + tcp_keepalive_s: 0, + http2_keepalive_interval_s: 0, + http2_keepalive_timeout_s: 0, + }], + store_type: StoreType::Cas, + retry: Retry::default(), + max_concurrent_requests: 0, + connections_per_endpoint: 0, + rpc_timeout_s: 0, + use_legacy_resource_names: false, + headers: HashMap::new(), + forward_headers: vec![], + experimental_read_batching: read_batching, + experimental_remote_cache_compression: Some(false), + }; + let store = GrpcStore::new(&spec).await?; + Ok(TestFixture { + cas_server, + bytestream_server, + store, + }) +} + +const fn batching_config() -> GrpcReadBatchingConfig { + GrpcReadBatchingConfig { + max_blob_size_bytes: 128 * 1024, + max_batch_bytes: 3 * 1024 * 1024, + dispatch_slots: 1, + max_queued_bytes: 32 * 1024 * 1024, + } +} + +/// Creates a unique digest and 64-byte content for blob index `i`. +fn make_blob(i: usize) -> (DigestInfo, Bytes) { + let hash = format!("{:064x}", i + 1); + let content = Bytes::from(format!("{i:0>64}")); + let digest = DigestInfo::try_new(&hash, content.len()).unwrap(); + (digest, content) +} + +async fn seed_blobs(fixture: &TestFixture, blobs: &[(DigestInfo, Bytes)]) { + let mut map = fixture.cas_server.blobs.lock().await; + for (digest, content) in blobs { + map.insert(digest.packed_hash().to_string(), content.clone()); + } +} + +// Many concurrent small reads must be coalesced into BatchReadBlobs RPCs +// and never touch the ByteStream Read path. +#[nativelink_test] +async fn small_blob_reads_are_batched() -> Result<(), Error> { + const NUM_BLOBS: usize = 200; + + let fixture = make_fixture(Some(batching_config())).await?; + let mut blobs = Vec::with_capacity(NUM_BLOBS); + for i in 0..NUM_BLOBS { + blobs.push(make_blob(i)); + } + seed_blobs(&fixture, &blobs).await; + + let mut read_futures = Vec::with_capacity(NUM_BLOBS); + for (digest, _) in &blobs { + read_futures.push(fixture.store.get_part_unchunked(*digest, 0, None)); + } + let results = futures::future::join_all(read_futures).await; + for (result, (_, expected_content)) in results.into_iter().zip(&blobs) { + assert_eq!(&result?, expected_content); + } + + let batch_read_requests = fixture.cas_server.batch_read_requests.lock().await; + assert!( + !batch_read_requests.is_empty(), + "Expected BatchReadBlobs to be used" + ); + let total_batched_digests: usize = batch_read_requests + .iter() + .map(|request| request.digests.len()) + .sum(); + assert_eq!(total_batched_digests, NUM_BLOBS); + assert!( + batch_read_requests.len() < NUM_BLOBS / 2, + "Expected reads to be coalesced, got {} BatchReadBlobs calls", + batch_read_requests.len() + ); + assert_eq!( + fixture.bytestream_server.read_requests.lock().await.len(), + 0, + "ByteStream Read must not be used for batched reads" + ); + Ok(()) +} + +// Blobs above max_blob_size_bytes must use the ByteStream Read path. +#[nativelink_test] +async fn large_blob_uses_stream_path() -> Result<(), Error> { + let mut config = batching_config(); + config.max_blob_size_bytes = 1024; + let fixture = make_fixture(Some(config)).await?; + + let hash = format!("{:064x}", 42_u32); + let content = Bytes::from(vec![42_u8; 2048]); + let digest = DigestInfo::try_new(&hash, content.len()).unwrap(); + seed_blobs(&fixture, &[(digest, content.clone())]).await; + + let data = fixture.store.get_part_unchunked(digest, 0, None).await?; + assert_eq!(data, content); + + assert_eq!( + fixture.bytestream_server.read_requests.lock().await.len(), + 1 + ); + assert_eq!(fixture.cas_server.batch_read_requests.lock().await.len(), 0); + Ok(()) +} + +// Partial reads (offset != 0) must bypass batching. +#[nativelink_test] +async fn partial_read_bypasses_batching() -> Result<(), Error> { + let fixture = make_fixture(Some(batching_config())).await?; + let (digest, content) = make_blob(7); + seed_blobs(&fixture, &[(digest, content.clone())]).await; + + let data = fixture.store.get_part_unchunked(digest, 1, None).await?; + assert_eq!(data, content.slice(1..)); + + let read_requests = fixture.bytestream_server.read_requests.lock().await; + assert_eq!(read_requests.len(), 1); + assert_eq!(read_requests[0].read_offset, 1); + assert_eq!(fixture.cas_server.batch_read_requests.lock().await.len(), 0); + Ok(()) +} + +// A NOT_FOUND for one digest in a batch must fail only that read; the +// other reads in the same batch must succeed. +#[nativelink_test] +async fn batch_item_failure_is_isolated() -> Result<(), Error> { + let fixture = make_fixture(Some(batching_config())).await?; + let (good_digest1, good_content1) = make_blob(1); + let (bad_digest, _) = make_blob(2); + let (good_digest2, good_content2) = make_blob(3); + seed_blobs( + &fixture, + &[ + (good_digest1, good_content1.clone()), + (good_digest2, good_content2.clone()), + ], + ) + .await; + fixture + .cas_server + .not_found_hashes + .lock() + .await + .push(bad_digest.packed_hash().to_string()); + + // On the single-threaded test runtime all three reads enqueue before + // the detached dispatcher task gets to run, so they coalesce. + let (good_result1, bad_result, good_result2) = futures::join!( + fixture.store.get_part_unchunked(good_digest1, 0, None), + fixture.store.get_part_unchunked(bad_digest, 0, None), + fixture.store.get_part_unchunked(good_digest2, 0, None), + ); + assert_eq!(good_result1?, good_content1); + assert_eq!(good_result2?, good_content2); + let bad_err = bad_result.expect_err("Expected NOT_FOUND digest to fail"); + assert_eq!(bad_err.code, Code::NotFound, "Got error: {bad_err:?}"); + + // Confirm that the failed digest actually shared a batch with another + // read (rather than each read getting its own RPC). + let batch_read_requests = fixture.cas_server.batch_read_requests.lock().await; + let bad_hash = bad_digest.packed_hash().to_string(); + assert!( + batch_read_requests + .iter() + .any(|request| request.digests.len() > 1 + && request.digests.iter().any(|d| d.hash == bad_hash)), + "Expected the failing digest to share a batch with other reads: {batch_read_requests:?}" + ); + assert_eq!( + fixture.bytestream_server.read_requests.lock().await.len(), + 0 + ); + Ok(()) +} + +// With batching unconfigured the store must behave exactly as before and +// never call BatchReadBlobs. +#[nativelink_test] +async fn disabled_batching_uses_stream_path() -> Result<(), Error> { + let fixture = make_fixture(None).await?; + let (digest, content) = make_blob(11); + seed_blobs(&fixture, &[(digest, content.clone())]).await; + + let data = fixture.store.get_part_unchunked(digest, 0, None).await?; + assert_eq!(data, content); + + assert_eq!( + fixture.bytestream_server.read_requests.lock().await.len(), + 1 + ); + assert_eq!(fixture.cas_server.batch_read_requests.lock().await.len(), 0); + Ok(()) +} + +// Cancelling one read mid-flight must not abort the shared batch RPC nor +// strand the other queued reads. +#[nativelink_test] +async fn cancelled_read_does_not_affect_batch_mates() -> Result<(), Error> { + let fixture = make_fixture(Some(batching_config())).await?; + let (cancelled_digest, cancelled_content) = make_blob(1); + let (digest_b, content_b) = make_blob(2); + let (digest_c, content_c) = make_blob(3); + seed_blobs( + &fixture, + &[ + (cancelled_digest, cancelled_content), + (digest_b, content_b.clone()), + (digest_c, content_c.clone()), + ], + ) + .await; + + // Poll one read just far enough to enqueue it, then drop it to + // simulate cancellation before its batch has been dispatched. + let waker = Waker::noop(); + let mut task_context = TaskContext::from_waker(waker); + let mut cancelled_read = Box::pin(fixture.store.get_part_unchunked(cancelled_digest, 0, None)); + assert!(cancelled_read.as_mut().poll(&mut task_context).is_pending()); + drop(cancelled_read); + + let (result_b, result_c) = futures::join!( + fixture.store.get_part_unchunked(digest_b, 0, None), + fixture.store.get_part_unchunked(digest_c, 0, None), + ); + assert_eq!(result_b?, content_b); + assert_eq!(result_c?, content_c); + assert_eq!( + fixture.bytestream_server.read_requests.lock().await.len(), + 0 + ); + Ok(()) +} + +// Concurrent reads of the same digest must all succeed even though the +// digest is requested only once per batch and the server responds with a +// single entry for it. +#[nativelink_test] +async fn duplicate_digest_reads_all_succeed() -> Result<(), Error> { + let fixture = make_fixture(Some(batching_config())).await?; + let (digest, content) = make_blob(5); + seed_blobs(&fixture, &[(digest, content.clone())]).await; + + let (result_a, result_b) = futures::join!( + fixture.store.get_part_unchunked(digest, 0, None), + fixture.store.get_part_unchunked(digest, 0, None), + ); + assert_eq!(result_a?, content); + assert_eq!(result_b?, content); + + // The client must dedupe: each request may carry the digest only once. + let batch_read_requests = fixture.cas_server.batch_read_requests.lock().await; + assert!(!batch_read_requests.is_empty()); + for request in batch_read_requests.iter() { + assert_eq!( + request.digests.len(), + 1, + "Expected deduped digests: {request:?}" + ); + } + assert_eq!( + fixture.bytestream_server.read_requests.lock().await.len(), + 0 + ); + Ok(()) +} + +// Batched reads share one upstream RPC, so combining them with per-client +// forwarded headers must be rejected at construction. +#[nativelink_test] +async fn forward_headers_with_batching_rejected() -> Result<(), Error> { + let spec = GrpcSpec { + instance_name: String::new(), + endpoints: vec![GrpcEndpoint { + address: "http://foobar".to_string(), + tls_config: None, + concurrency_limit: None, + connect_timeout_s: 0, + tcp_keepalive_s: 0, + http2_keepalive_interval_s: 0, + http2_keepalive_timeout_s: 0, + }], + store_type: StoreType::Cas, + retry: Retry::default(), + max_concurrent_requests: 0, + connections_per_endpoint: 0, + rpc_timeout_s: 0, + use_legacy_resource_names: false, + headers: HashMap::new(), + forward_headers: vec!["authorization".to_string()], + experimental_read_batching: Some(batching_config()), + experimental_remote_cache_compression: Some(false), + }; + let err = GrpcStore::new(&spec) + .await + .expect_err("Expected construction to fail"); + assert_eq!(err.code, Code::InvalidArgument, "Got error: {err:?}"); + Ok(()) +} diff --git a/nativelink-store/tests/grpc_store_test.rs b/nativelink-store/tests/grpc_store_test.rs index 3466997b2..7393f604a 100644 --- a/nativelink-store/tests/grpc_store_test.rs +++ b/nativelink-store/tests/grpc_store_test.rs @@ -4,13 +4,20 @@ use std::collections::HashMap; use std::sync::Arc; use async_lock::Mutex; -use futures::stream::unfold; +use futures::stream::{self, unfold}; use futures::{Stream, StreamExt}; use nativelink_config::stores::{GrpcEndpoint, GrpcSpec, Retry, StoreType}; use nativelink_error::{Error, ResultExt}; use nativelink_macro::nativelink_test; +use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_storage_server::{ + ContentAddressableStorage, ContentAddressableStorageServer, +}; use nativelink_proto::build::bazel::remote::execution::v2::{ - FindMissingBlobsRequest, digest_function, + BatchReadBlobsRequest, BatchReadBlobsResponse, BatchUpdateBlobsRequest, + BatchUpdateBlobsResponse, Digest, FindMissingBlobsRequest, FindMissingBlobsResponse, + GetTreeRequest, GetTreeResponse, SpliceBlobRequest, SpliceBlobResponse, SplitBlobRequest, + SplitBlobResponse, batch_update_blobs_request, batch_update_blobs_response, chunking_function, + compressor, digest_function, }; use nativelink_proto::google::bytestream::byte_stream_server::{ByteStream, ByteStreamServer}; use nativelink_proto::google::bytestream::{ @@ -21,6 +28,7 @@ use nativelink_store::grpc_store::GrpcStore; use nativelink_util::background_spawn; use nativelink_util::buf_channel::make_buf_channel_pair; use nativelink_util::common::DigestInfo; +use nativelink_util::proto_stream_utils::WriteRequestStreamWrapper; use nativelink_util::store_trait::{StoreLike, UploadSizeInfo}; use nativelink_util::telemetry::ClientHeaders; use opentelemetry::Context; @@ -55,6 +63,8 @@ fn test_spec>(endpoint: T, use_legacy_resource_names: bool) -> G use_legacy_resource_names, headers: HashMap::new(), forward_headers: vec![], + experimental_read_batching: None, + experimental_remote_cache_compression: Some(false), } } @@ -86,6 +96,9 @@ struct ReadRequestHolder { struct FakeStreamServer { write_requests: Arc>>, read_requests: Arc>>, + /// Record every `WriteRequest`, not just the first, so a test can assert + /// on how the client chunked the stream. + drain_all: bool, } impl FakeStreamServer { @@ -93,6 +106,14 @@ impl FakeStreamServer { Self { write_requests: Arc::new(Mutex::new(vec![])), read_requests: Arc::new(Mutex::new(vec![])), + drain_all: false, + } + } + + fn new_draining() -> Self { + Self { + drain_all: true, + ..Self::new() } } } @@ -148,7 +169,17 @@ impl ByteStream for FakeStreamServer { &self, grpc_request: Request>, ) -> Result, Status> { - let write_request = match grpc_request.into_inner().next().await { + let mut stream = grpc_request.into_inner(); + if self.drain_all { + let mut committed_size = 0i64; + while let Some(req) = stream.next().await { + let req = req?; + committed_size += i64::try_from(req.data.len()).unwrap(); + self.write_requests.lock().await.push(req); + } + return Ok(Response::new(WriteResponse { committed_size })); + } + let write_request = match stream.next().await { None => { return Err(Status::unknown("Client closed stream")); } @@ -156,7 +187,7 @@ impl ByteStream for FakeStreamServer { Some(Ok(write_request)) => write_request, }; info!(?write_request, "write request"); - let committed_size = write_request.data.len() as i64; + let committed_size = write_request.data.len().try_into().unwrap_or(i64::MAX); self.write_requests.lock().await.push(write_request); Ok(Response::new(WriteResponse { committed_size })) } @@ -170,8 +201,15 @@ impl ByteStream for FakeStreamServer { } } +async fn make_fake_bytestream_server_draining() -> (FakeStreamServer, u16) { + spawn_bytestream_server(FakeStreamServer::new_draining()).await +} + async fn make_fake_bytestream_server() -> (FakeStreamServer, u16) { - let fake_stream_server = FakeStreamServer::new(); + spawn_bytestream_server(FakeStreamServer::new()).await +} + +async fn spawn_bytestream_server(fake_stream_server: FakeStreamServer) -> (FakeStreamServer, u16) { let server = ByteStreamServer::new(fake_stream_server.clone()); let listener = TcpIncoming::bind("127.0.0.1:0".parse().unwrap()).unwrap(); let port = listener.local_addr().unwrap().port(); @@ -322,3 +360,395 @@ async fn read_works_with_headers() -> Result<(), Error> { Ok(()) } + +#[derive(Debug, Clone)] +struct FakeCasServer { + split_requests: Arc>>, + splice_requests: Arc>>, + /// Every `BatchUpdateBlobs` RPC received, so a test can assert on how the + /// store split an oversized batch. + batch_updates: Arc>>, +} + +impl FakeCasServer { + fn new() -> Self { + Self { + split_requests: Arc::new(Mutex::new(vec![])), + splice_requests: Arc::new(Mutex::new(vec![])), + batch_updates: Arc::new(Mutex::new(vec![])), + } + } +} + +type GetTreeStream = Pin> + Send + 'static>>; + +#[tonic::async_trait] +impl ContentAddressableStorage for FakeCasServer { + type GetTreeStream = GetTreeStream; + + #[allow(clippy::unimplemented)] + async fn find_missing_blobs( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + async fn batch_update_blobs( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + // One response per entry, echoing the digest, so a test can check the + // stitched-together result keeps request order. + let responses = request + .requests + .iter() + .map(|r| batch_update_blobs_response::Response { + digest: r.digest.clone(), + status: None, + }) + .collect(); + self.batch_updates.lock().await.push(request); + Ok(Response::new(BatchUpdateBlobsResponse { responses })) + } + + #[allow(clippy::unimplemented)] + async fn batch_read_blobs( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + #[allow(clippy::unimplemented)] + async fn get_tree( + &self, + _grpc_request: Request, + ) -> Result, Status> { + unimplemented!(); + } + + async fn split_blob( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + self.split_requests.lock().await.push(request.clone()); + Ok(Response::new(SplitBlobResponse { + chunk_digests: request.blob_digest.into_iter().collect(), + chunking_function: request.chunking_function, + })) + } + + async fn splice_blob( + &self, + grpc_request: Request, + ) -> Result, Status> { + let request = grpc_request.into_inner(); + self.splice_requests.lock().await.push(request.clone()); + Ok(Response::new(SpliceBlobResponse { + blob_digest: request.blob_digest, + })) + } +} + +async fn make_fake_cas_server() -> (FakeCasServer, u16) { + let fake_cas_server = FakeCasServer::new(); + let server = ContentAddressableStorageServer::new(fake_cas_server.clone()); + let listener = TcpIncoming::bind("127.0.0.1:0".parse().unwrap()).unwrap(); + let port = listener.local_addr().unwrap().port(); + + background_spawn!("server", async move { + Server::builder() + .add_service(server) + .serve_with_incoming(listener) + .await + .unwrap(); + }); + + (fake_cas_server, port) +} + +#[nativelink_test] +async fn split_and_splice_blob_forward_to_backend() -> Result<(), Error> { + let (server, port) = make_fake_cas_server().await; + let mut spec = test_spec(format!("http://localhost:{port}"), false); + spec.instance_name = "backend_instance".to_string(); + let store = GrpcStore::new(&spec).await?; + + let digest = Digest { + hash: VALID_HASH.to_string(), + size_bytes: RAW_INPUT.len().try_into().unwrap_or(i64::MAX), + }; + + let split_response = store + .split_blob(Request::new(SplitBlobRequest { + instance_name: "local_instance".to_string(), + blob_digest: Some(digest.clone()), + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(split_response.chunk_digests, vec![digest.clone()]); + { + let split_requests = server.split_requests.lock().await; + assert_eq!(split_requests.len(), 1); + // The instance name must be rewritten to the backend's. + assert_eq!(split_requests[0].instance_name, "backend_instance"); + } + + let splice_response = store + .splice_blob(Request::new(SpliceBlobRequest { + instance_name: "local_instance".to_string(), + blob_digest: Some(digest.clone()), + chunk_digests: vec![digest.clone()], + digest_function: digest_function::Value::Sha256.into(), + chunking_function: chunking_function::Value::FastCdc2020.into(), + })) + .await? + .into_inner(); + assert_eq!(splice_response.blob_digest, Some(digest)); + { + let splice_requests = server.splice_requests.lock().await; + assert_eq!(splice_requests.len(), 1); + assert_eq!(splice_requests[0].instance_name, "backend_instance"); + } + Ok(()) +} + +/// A whole-blob write (`update_oneshot`, how a worker uploads stdout) must not +/// become one giant `WriteRequest`: receivers cap decoded message size and +/// reject an oversized message outright rather than degrading. +#[nativelink_test] +async fn update_splits_buffers_larger_than_the_grpc_message_limit() -> Result<(), Error> { + const TONIC_DEFAULT_DECODE_LIMIT: usize = 4 * 1024 * 1024; + // Over the limit, and not a multiple of the chunk size so the last piece + // is a partial one. + const BLOB_LEN: usize = 9_869_079; + + let (server, port) = make_fake_bytestream_server_draining().await; + let mut spec = test_spec(format!("http://localhost:{port}"), false); + // This test moves and reassembles almost 10 MiB under instrumented builds. + // Keep the RPC deadline comfortably above sanitizer overhead; timeout + // behavior is not what this test exercises. + spec.rpc_timeout_s = 5; + let store = GrpcStore::new(&spec).await?; + let digest = DigestInfo::try_new(VALID_HASH, BLOB_LEN).unwrap(); + + let payload = vec![0xABu8; BLOB_LEN]; + let (mut tx, rx) = make_buf_channel_pair(); + let send_payload = payload.clone(); + let send_fut = async move { + // One write of the entire blob, exactly what update_oneshot does. + tx.send(send_payload.into()).await?; + tx.send_eof() + }; + let (res1, res2) = futures::join!( + send_fut, + store.update( + digest, + rx, + UploadSizeInfo::ExactSize(BLOB_LEN.try_into().unwrap()) + ) + ); + res1.merge(res2)?; + + let write_requests = server.write_requests.lock().await; + assert!( + write_requests.len() > 1, + "expected the blob to be split across several WriteRequests, got {}", + write_requests.len() + ); + + for (i, req) in write_requests.iter().enumerate() { + assert!( + req.data.len() <= TONIC_DEFAULT_DECODE_LIMIT, + "WriteRequest {i} carries {} bytes, over the {TONIC_DEFAULT_DECODE_LIMIT} byte default decode limit", + req.data.len() + ); + } + + // Contiguous offsets and identical bytes: the split must not corrupt or + // reorder the blob. + let mut reassembled = Vec::with_capacity(BLOB_LEN); + let mut expected_offset = 0i64; + for req in write_requests.iter() { + assert_eq!( + req.write_offset, expected_offset, + "write_offset must be contiguous across chunks" + ); + expected_offset += i64::try_from(req.data.len()).unwrap(); + reassembled.extend_from_slice(&req.data); + } + assert_eq!(reassembled.len(), BLOB_LEN); + assert_eq!( + reassembled, payload, + "reassembled blob must match the input" + ); + + // Exactly one terminator, and it must be the last message. + let finish_flags: Vec = write_requests.iter().map(|r| r.finish_write).collect(); + assert_eq!( + finish_flags.iter().filter(|f| **f).count(), + 1, + "expected exactly one finish_write, got {finish_flags:?}" + ); + assert!( + *finish_flags.last().unwrap(), + "finish_write must be on the final message" + ); + Ok(()) +} + +/// The `ByteStream` pass-through forwards the caller's frames as it receives +/// them, so a caller that hands over a whole blob in one frame would produce +/// one oversized message and be rejected at the receiver's 4MiB default. +#[nativelink_test] +async fn write_splits_frames_larger_than_the_grpc_message_limit() -> Result<(), Error> { + const TONIC_DEFAULT_DECODE_LIMIT: usize = 4 * 1024 * 1024; + // Over the limit and not a multiple of the chunk size, so the tail is a + // partial piece. Kept just past the limit rather than at the ~9.4MB seen + // in the wild: the extra bytes prove nothing here and cost real time under + // sanitizers. + const BLOB_LEN: usize = 5_242_883; + + let (server, port) = make_fake_bytestream_server_draining().await; + let mut spec = test_spec(format!("http://localhost:{port}"), false); + // Streaming several MiB through ByteStream is slow under instrumented + // builds. This deadline is headroom for that, not part of the test. + spec.rpc_timeout_s = 30; + let store = GrpcStore::new(&spec).await?; + + let payload = vec![0xCDu8; BLOB_LEN]; + let resource_name = format!( + "instance_name/uploads/{}/blobs/{VALID_HASH}/{BLOB_LEN}", + uuid::Uuid::new_v4() + ); + // A single frame carrying the entire blob, which is what a client doing + // one big write looks like on the wire. + let requests = vec![WriteRequest { + resource_name, + write_offset: 0, + finish_write: true, + data: payload.clone().into(), + }]; + let stream = + WriteRequestStreamWrapper::from(stream::iter(requests.into_iter().map(Ok::<_, Error>))) + .await?; + + store.write(stream).await?; + + let write_requests = server.write_requests.lock().await; + assert!( + write_requests.len() > 1, + "expected the frame to be split, got {}", + write_requests.len() + ); + + for (i, req) in write_requests.iter().enumerate() { + assert!( + req.data.len() <= TONIC_DEFAULT_DECODE_LIMIT, + "WriteRequest {i} carries {} bytes, over the {TONIC_DEFAULT_DECODE_LIMIT} byte default decode limit", + req.data.len() + ); + } + + let mut reassembled = Vec::with_capacity(BLOB_LEN); + let mut expected_offset = 0i64; + for req in write_requests.iter() { + assert_eq!( + req.write_offset, expected_offset, + "write_offset must be contiguous across chunks" + ); + expected_offset += i64::try_from(req.data.len()).unwrap(); + reassembled.extend_from_slice(&req.data); + } + assert_eq!(reassembled, payload, "the split must not corrupt the blob"); + + let finish_flags: Vec = write_requests.iter().map(|r| r.finish_write).collect(); + assert_eq!( + finish_flags.iter().filter(|f| **f).count(), + 1, + "expected exactly one finish_write, got {finish_flags:?}" + ); + assert!( + *finish_flags.last().unwrap(), + "finish_write must be on the final chunk" + ); + Ok(()) +} + +/// A batch is a single message, so an oversized one has to become several +/// RPCs rather than several chunks of one RPC. +#[nativelink_test] +async fn batch_update_blobs_splits_an_oversized_batch_across_rpcs() -> Result<(), Error> { + const TONIC_DEFAULT_DECODE_LIMIT: usize = 4 * 1024 * 1024; + const ENTRY_LEN: usize = 900 * 1024; + const ENTRIES: usize = 12; // ~10.5MiB total, comfortably over the limit. + + let (server, port) = make_fake_cas_server().await; + let mut spec = test_spec(format!("http://localhost:{port}"), false); + spec.instance_name = "backend_instance".to_string(); + spec.rpc_timeout_s = 5; + let store = GrpcStore::new(&spec).await?; + + let requests: Vec = (0..ENTRIES) + .map(|i| batch_update_blobs_request::Request { + digest: Some(Digest { + hash: format!("{i:064x}"), + size_bytes: i64::try_from(ENTRY_LEN).unwrap(), + }), + data: vec![u8::try_from(i).unwrap_or(0); ENTRY_LEN].into(), + compressor: compressor::Value::Identity.into(), + }) + .collect(); + let expected_digests: Vec> = requests.iter().map(|r| r.digest.clone()).collect(); + + let response = store + .batch_update_blobs(Request::new(BatchUpdateBlobsRequest { + instance_name: "local_instance".to_string(), + requests, + digest_function: digest_function::Value::Sha256.into(), + })) + .await?; + + let batches = server.batch_updates.lock().await; + assert!( + batches.len() > 1, + "expected the batch to be split across several RPCs, got {}", + batches.len() + ); + + for (i, batch) in batches.iter().enumerate() { + let bytes: usize = batch.requests.iter().map(|r| r.data.len()).sum(); + assert!( + bytes <= TONIC_DEFAULT_DECODE_LIMIT, + "batch {i} carries {bytes} bytes, over the {TONIC_DEFAULT_DECODE_LIMIT} byte default decode limit", + ); + assert_eq!( + batch.instance_name, "backend_instance", + "every split batch keeps the rewritten instance name" + ); + } + + // Nothing dropped or reordered by the split. + let sent: Vec> = batches + .iter() + .flat_map(|b| b.requests.iter().map(|r| r.digest.clone())) + .collect(); + assert_eq!(sent, expected_digests, "every blob must be forwarded once"); + + let got: Vec> = response + .into_inner() + .responses + .into_iter() + .map(|r| r.digest) + .collect(); + assert_eq!( + got, expected_digests, + "stitched responses must stay in request order" + ); + Ok(()) +} diff --git a/nativelink-store/tests/memory_store_test.rs b/nativelink-store/tests/memory_store_test.rs index 996e94736..069ea59e1 100644 --- a/nativelink-store/tests/memory_store_test.rs +++ b/nativelink-store/tests/memory_store_test.rs @@ -117,7 +117,7 @@ fn store_with_max_bytes(max_bytes: usize) -> Store { })) } -// A write whose exact size is >= max_bytes is skipped (drained, never buffered) +// A write whose exact size is >= `max_bytes` is skipped (drained, never buffered) // rather than materialized-then-evicted, and — crucially — it leaves the rest of // the cache untouched (the old buffer-then-evict path would have evicted the // within-budget entry trying to make room for an unstorable blob). @@ -207,7 +207,7 @@ async fn oversized_skip_fires_remove_callbacks() -> Result<(), Error> { } // `MaxSize` is an upper bound, not the real size, so it must NOT trigger the skip: -// a MaxSize over max_bytes whose actual content fits is still cached. +// a `MaxSize` over `max_bytes` whose actual content fits is still cached. #[nativelink_test] async fn max_size_over_budget_with_small_actual_is_stored() -> Result<(), Error> { const DATA: &[u8] = b"ab"; // 2 bytes, well within the 4-byte budget diff --git a/nativelink-store/tests/mongo_runner/downloader.rs b/nativelink-store/tests/mongo_runner/downloader.rs index 967cf884a..b3ca9f628 100644 --- a/nativelink-store/tests/mongo_runner/downloader.rs +++ b/nativelink-store/tests/mongo_runner/downloader.rs @@ -78,10 +78,10 @@ pub(crate) fn get_download_url(version: &str) -> Result { // Refined logic let url = match (&os, &arch) { (Os::Linux, Arch::X86_64) => { - format!("{base_url}/linux/mongodb-linux-x86_64-ubuntu2204-{version}.tgz",) + format!("{base_url}/linux/mongodb-linux-x86_64-ubuntu2204-{version}.tgz") } (Os::Linux, Arch::Aarch64) => { - format!("{base_url}/linux/mongodb-linux-aarch64-ubuntu2204-{version}.tgz",) + format!("{base_url}/linux/mongodb-linux-aarch64-ubuntu2204-{version}.tgz") } (Os::MacOs, Arch::X86_64) => { format!("{base_url}/osx/mongodb-macos-x86_64-{version}.tgz") @@ -122,6 +122,12 @@ where use std::fs::File; use std::io::Write; + // reqwest is built with `rustls-no-provider`, so it panics when building a + // client unless a rustls crypto provider is installed as the process default. + // The server binary installs one at startup; this download runs before any + // store does, so install it here too. Idempotent: ignores the already-set case. + drop(rustls::crypto::ring::default_provider().install_default()); + let response = reqwest::get(url).await?; let total = response.content_length(); diff --git a/nativelink-store/tests/mongo_runner/mod.rs b/nativelink-store/tests/mongo_runner/mod.rs index 035896ca7..35cb9e66b 100644 --- a/nativelink-store/tests/mongo_runner/mod.rs +++ b/nativelink-store/tests/mongo_runner/mod.rs @@ -7,15 +7,17 @@ pub(crate) mod process; use core::time::Duration; use std::fs; use std::path::PathBuf; -use std::sync::{Condvar, LazyLock, Mutex}; +use std::sync::LazyLock; pub(crate) use downloader::DownloadProgress; use downloader::{download_file_with_callback, get_download_url, get_os}; use extractor::extract; -use mongodb::bson::doc; +use mongodb::bson::{Bson, doc}; use nativelink_error::{Error, ResultExt, make_err}; use process::MongoProcess; use tempfile::tempdir; +use tokio::fs::read_to_string; +use tokio::sync::Mutex; use tonic::Code; use tracing::{debug, info}; @@ -36,14 +38,27 @@ pub(crate) struct MongoEmbedded { pub download_path: PathBuf, pub extract_path: PathBuf, pub db_path: PathBuf, + /// Port to bind. 0 means pick a free ephemeral port at start time (and + /// pick a fresh one if a bind race is lost). The port that was actually + /// bound is reflected in the returned process's `connection_string`. pub port: u16, pub bind_ip: String, pub username: Option, pub password: Option, } -static CURRENTLY_DOWNLOADING: LazyLock<(Mutex, Condvar)> = - LazyLock::new(|| (Mutex::new(false), Condvar::new())); +/// Serializes download+extract across concurrently running tests in this +/// process. The `extracted.marker` file is the completion predicate: re-check +/// it after acquiring the lock, because another test may have completed the +/// download while we waited. If a download fails the lock is simply released, +/// so the next waiter retries instead of hanging forever. +static DOWNLOAD_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); + +/// An ephemeral port is released back to the OS before mongod binds it, so +/// another process can grab it in between. When that happens our mongod exits +/// (or a foreign server answers on the port); `wait_until_ready` detects both, +/// and we retry with a fresh port. +const MAX_SPAWN_ATTEMPTS: u32 = 5; impl MongoEmbedded { pub(crate) fn new(version: &str) -> Self { @@ -60,7 +75,7 @@ impl MongoEmbedded { download_path: cache_dir.join("downloads"), extract_path: cache_dir.join("extracted"), db_path, - port: 27017, + port: 0, bind_ip: "127.0.0.1".to_string(), username: None, password: None, @@ -116,19 +131,10 @@ impl MongoEmbedded { if extract_marker.exists() { info!(?extract_marker, "Already have Mongo downloaded"); } else { - let existing_downloader = { - let mut lock = CURRENTLY_DOWNLOADING.0.lock().unwrap(); - if *lock { - info!("Waiting for downloader"); - let _guard = CURRENTLY_DOWNLOADING.1.wait(lock)?; - true - } else { - info!("First here so, downloading Mongo"); - *lock = true; - false - } - }; - if !existing_downloader { + let _download_guard = DOWNLOAD_LOCK.lock().await; + // Re-check under the lock: another test may have just finished + // downloading while we waited for the lock. + if !extract_marker.exists() { if !self.download_path.exists() { fs::create_dir_all(&self.download_path) .err_tip(|| format!("Making {}", self.download_path.display()))?; @@ -154,91 +160,68 @@ impl MongoEmbedded { extract_target.display() ) })?; - info!("Downloaded, notifying"); fs::write(extract_marker, "")?; - let lock = CURRENTLY_DOWNLOADING.0.lock().unwrap(); - CURRENTLY_DOWNLOADING.1.notify_all(); - drop(lock); + info!("Downloaded and extracted Mongo"); } } let os = get_os()?; + let auth_enabled = self.username.is_some() && self.password.is_some(); - // Calculate initial connection string for readiness check #[allow(clippy::case_sensitive_file_extension_comparisons)] - let uri = if self.bind_ip.contains('/') || self.bind_ip.ends_with(".sock") { - // Assume unix socket - // Minimal URL encoding for path, replacing / with %2F. - // This is required for the rust mongodb driver to recognize it as a socket. - // Note: When using sockets with mongodb crate, we often need to ensure the host is just the encoded path. - let encoded = self.bind_ip.replace('/', "%2F"); - format!("mongodb://{encoded}/?directConnection=true") - } else { - format!( - "mongodb://{}:{}/?directConnection=true", - self.bind_ip, self.port + let is_unix_socket = self.bind_ip.contains('/') || self.bind_ip.ends_with(".sock"); + + let mut process = None; + let mut last_error = make_err!(Code::Internal, "mongod was never spawned"); + for attempt in 0..MAX_SPAWN_ATTEMPTS { + let port = if is_unix_socket || self.port != 0 { + self.port + } else { + get_ephemeral_port()? + }; + let uri = if is_unix_socket { + // Minimal URL encoding for path, replacing / with %2F. + // This is required for the rust mongodb driver to recognize it as a socket. + // Note: When using sockets with mongodb crate, we often need to ensure the host is just the encoded path. + let encoded = self.bind_ip.replace('/', "%2F"); + format!("mongodb://{encoded}/?directConnection=true") + } else { + format!("mongodb://{}:{port}/?directConnection=true", self.bind_ip) + }; + + let mut candidate = MongoProcess::start( + &extract_target, + port, + &self.db_path, + &os, + &self.bind_ip, + auth_enabled, + uri, ) - }; + .err_tip(|| format!("Starting mongo from {}", extract_target.display()))?; - // Start process with auth flag if credentials are requested - let auth_enabled = self.username.is_some() && self.password.is_some(); - let mut process = MongoProcess::start( - &extract_target, - self.port, - &self.db_path, - &os, - &self.bind_ip, - auth_enabled, - uri.clone(), - ) - .err_tip(|| format!("Starting mongo from {}", extract_target.display()))?; - - // Need to wait for it to be ready - // We can try to connect - let mut client_options = mongodb::options::ClientOptions::parse(&uri).await?; - client_options.connect_timeout = Some(Duration::from_secs(2)); - client_options.server_selection_timeout = Some(Duration::from_secs(2)); - - // Simple loop to wait for readiness - let mut connected = false; - let start = std::time::Instant::now(); - debug!("Waiting for MongoDB to start at {uri}"); - while start.elapsed() < Duration::from_secs(30) { - let client = mongodb::Client::with_options(client_options.clone())?; - match client.list_database_names().await { - Ok(_) => { - connected = true; - debug!("Connected to MongoDB at {uri}"); + match wait_until_ready(&mut candidate, auth_enabled).await { + Ok(()) => { + process = Some(candidate); break; } - Err(e) => { - debug!("Connection attempt failed: {:?}", e); - // If unauthorized error, it means we are connected but need auth, which is fine for readiness check - // "Unauthorized" usually is error code 13 - if let mongodb::error::ErrorKind::Command(ref cmd_err) = *e.kind - && (cmd_err.code == 51 || cmd_err.code == 13 || cmd_err.code == 18) - { - // 51: UserAlreadyExists?, 13: Unauthorized, 18: AuthFailed - connected = true; - break; - } + // Dropping `candidate` kills the failed process. + Err(err) => { + let logs = read_to_string(&candidate.log_path) + .await + .unwrap_or_else(|e| format!("Error reading {}: {e}", candidate.log_path)); + debug!(attempt, ?err, logs, "mongod did not become ready"); + last_error = err; } } - - tokio::time::sleep(Duration::from_millis(500)).await; - } - - if !connected { - debug!("Timed out waiting for start."); - process.kill()?; - return Err(make_err!( - Code::DeadlineExceeded, - "Timed out waiting for MongoDB to start" - )); } + let Some(mut process) = process else { + return Err(last_error); + }; if let (Some(username), Some(password)) = (&self.username, &self.password) { callback(InitStatus::SettingUpUser); + let client_options = ready_client_options(&process.connection_string).await?; let client = mongodb::Client::with_options(client_options.clone())?; // Try to create user. This only works if localhost exception is active (no users) @@ -258,10 +241,9 @@ impl MongoEmbedded { // Created user successfully } Err(_e) => { - // if needs_verify { callback(InitStatus::VerifyingCredentials); // Try to authenticate - let mut auth_opts = client_options.clone(); + let mut auth_opts = client_options; auth_opts.credential = Some( mongodb::options::Credential::builder() .username(username.clone()) @@ -271,13 +253,13 @@ impl MongoEmbedded { ); let auth_client = mongodb::Client::with_options(auth_opts)?; - // Verify by running a command that requires auth + // Verify by running a command that requires auth. Returning + // an error drops `process`, which kills the mongod. if let Err(auth_err) = auth_client .database("admin") .run_command(doc! { "ping": 1 }) .await { - process.kill()?; return Err(make_err!( Code::PermissionDenied, "Authentication failed or invalid credentials provided: {}", @@ -288,16 +270,14 @@ impl MongoEmbedded { } // Update connection string to include credentials - - #[allow(clippy::case_sensitive_file_extension_comparisons)] - let final_uri = if self.bind_ip.contains('/') || self.bind_ip.ends_with(".sock") { + let final_uri = if is_unix_socket { let encoded = self.bind_ip.replace('/', "%2F"); // For sockets, credentials go in the beginning format!("mongodb://{username}:{password}@{encoded}") } else { format!( "mongodb://{username}:{password}@{}:{}/", - self.bind_ip, self.port + self.bind_ip, process.port ) }; process.connection_string = final_uri; @@ -307,3 +287,98 @@ impl MongoEmbedded { Ok(process) } } + +/// Ask the OS for a currently-free TCP port. +fn get_ephemeral_port() -> Result { + let listener = std::net::TcpListener::bind(("127.0.0.1", 0)) + .err_tip(|| "Binding an ephemeral port for mongod")?; + Ok(listener + .local_addr() + .err_tip(|| "Getting ephemeral port for mongod")? + .port()) +} + +/// Client options with short per-attempt timeouts so the readiness poll reacts +/// quickly; the overall deadline is enforced by `wait_until_ready`'s loop. +async fn ready_client_options(uri: &str) -> Result { + let mut client_options = mongodb::options::ClientOptions::parse(uri).await?; + client_options.connect_timeout = Some(Duration::from_millis(500)); + client_options.server_selection_timeout = Some(Duration::from_millis(500)); + Ok(client_options) +} + +/// Waits until the just-spawned mongod answers on its connection string. Fails +/// fast if the process exits (e.g. it lost a bind race for its port) and +/// verifies the server answering is actually the process we spawned rather +/// than a foreign server that won the port. +async fn wait_until_ready(process: &mut MongoProcess, auth_enabled: bool) -> Result<(), Error> { + let uri = process.connection_string.clone(); + let client_options = ready_client_options(&uri).await?; + + let start = std::time::Instant::now(); + debug!("Waiting for MongoDB to start at {uri}"); + while start.elapsed() < Duration::from_secs(30) { + // A successful connection after our child died would be to whatever + // foreign process owns the port now, so check liveness first. + if let Some(status) = process.try_wait()? { + return Err(make_err!( + Code::Internal, + "mongod exited during startup with {status}" + )); + } + + let client = mongodb::Client::with_options(client_options.clone())?; + match client.list_database_names().await { + Ok(_) => { + // With auth enabled we can't run serverStatus before + // credentials exist, so skip the identity check there. + if auth_enabled || is_our_mongod(&client, process).await? { + debug!("Connected to MongoDB at {uri}"); + return Ok(()); + } + return Err(make_err!( + Code::Internal, + "A different process is serving mongod's port" + )); + } + Err(e) => { + debug!("Connection attempt failed: {:?}", e); + // If unauthorized error, it means we are connected but need auth, which is fine for readiness check + // "Unauthorized" usually is error code 13 + if let mongodb::error::ErrorKind::Command(ref cmd_err) = *e.kind + && (cmd_err.code == 51 || cmd_err.code == 13 || cmd_err.code == 18) + { + // 51: UserAlreadyExists?, 13: Unauthorized, 18: AuthFailed + return Ok(()); + } + } + } + + tokio::time::sleep(Duration::from_millis(100)).await; + } + + Err(make_err!( + Code::DeadlineExceeded, + "Timed out waiting for MongoDB to start" + )) +} + +/// Compares `serverStatus.pid` against the pid of the child we spawned. +async fn is_our_mongod(client: &mongodb::Client, process: &MongoProcess) -> Result { + let status = client + .database("admin") + .run_command(doc! { "serverStatus": 1 }) + .await + .map_err(|e| make_err!(Code::Internal, "serverStatus failed: {e}"))?; + let server_pid = match status.get("pid") { + Some(Bson::Int64(pid)) => *pid, + Some(Bson::Int32(pid)) => i64::from(*pid), + other => { + return Err(make_err!( + Code::Internal, + "serverStatus returned unparsable pid: {other:?}" + )); + } + }; + Ok(server_pid == i64::from(process.id())) +} diff --git a/nativelink-store/tests/mongo_runner/process.rs b/nativelink-store/tests/mongo_runner/process.rs index 44fbb2463..33975fca7 100644 --- a/nativelink-store/tests/mongo_runner/process.rs +++ b/nativelink-store/tests/mongo_runner/process.rs @@ -1,6 +1,6 @@ use std::fs; use std::path::{Path, PathBuf}; -use std::process::{Child, Command}; +use std::process::{Child, Command, ExitStatus}; use nativelink_error::{Error, ResultExt, make_err}; use tonic::Code; @@ -13,6 +13,9 @@ use super::downloader::Os; pub(crate) struct MongoProcess { child: Child, pub connection_string: String, + /// The TCP port this mongod was asked to bind (0 for unix sockets). + pub port: u16, + pub log_path: String, } impl MongoProcess { @@ -80,7 +83,23 @@ impl MongoProcess { .arg("--dbpath") .arg(db_path) .arg("--bind_ip") - .arg(bind_ip); + .arg(bind_ip) + // Tests run many mongod instances concurrently; without a cap each + // instance sizes its WiredTiger cache off total system memory + // (~50% of RAM - 1GB), starving parallel tests. + .arg("--wiredTigerCacheSizeGB") + .arg("0.25"); + + #[cfg(not(windows))] + { + #[allow(clippy::case_sensitive_file_extension_comparisons)] + let is_unix_socket = bind_ip.contains('/') || bind_ip.ends_with(".sock"); + if !is_unix_socket { + // Skip the default /tmp/mongodb-.sock; TCP is all we use and + // sandboxed CI may not allow writing to /tmp. + command.arg("--nounixsocket"); + } + } if auth { command.arg("--auth"); @@ -88,9 +107,10 @@ impl MongoProcess { let log_path = db_path .join(format!("mongo-{}.log", Uuid::new_v4().as_simple())) - .into_os_string(); + .to_string_lossy() + .to_string(); info!(?log_path, "Logging mongo"); - command.arg("--quiet").arg("--logpath").arg(log_path); + command.arg("--quiet").arg("--logpath").arg(&log_path); let child = command .spawn() @@ -99,9 +119,20 @@ impl MongoProcess { Ok(Self { child, connection_string, + port, + log_path, }) } + pub(crate) fn id(&self) -> u32 { + self.child.id() + } + + /// Returns `Some(status)` if the child has exited. + pub(crate) fn try_wait(&mut self) -> Result, Error> { + Ok(self.child.try_wait()?) + } + pub(crate) fn kill(&mut self) -> Result<(), Error> { self.child.kill()?; self.child.wait()?; @@ -109,6 +140,24 @@ impl MongoProcess { } } +impl Drop for MongoProcess { + fn drop(&mut self) { + // Kill the child on every exit path (a mongod left behind keeps its + // port and memory for the rest of the test binary's life, or longer). + // Never panic here: Drop also runs while unwinding from a failed test + // assertion, and a double panic aborts the whole test binary. + if let Ok(Some(_)) = self.child.try_wait() { + return; // Already exited and reaped. + } + if let Err(e) = self.child.kill() { + eprintln!("Failed to kill mongod: {e}"); + } + if let Err(e) = self.child.wait() { + eprintln!("Failed to reap mongod: {e}"); + } + } +} + fn find_binary(root: &Path, name: &str) -> Option { if root.is_file() { if root.file_name()?.to_str()? == name { diff --git a/nativelink-store/tests/mongo_store_test.rs b/nativelink-store/tests/mongo_store_test.rs index 9d1c6220a..dac6689d4 100644 --- a/nativelink-store/tests/mongo_store_test.rs +++ b/nativelink-store/tests/mongo_store_test.rs @@ -77,8 +77,10 @@ fn create_test_spec_with_key_prefix( } // Helper to keep hold of Mongo process parts so we don't accidentally drop them! +// Dropping MongoProcess kills the mongod, so owning these IS the cleanup. #[derive(Debug)] pub(crate) struct MongoParts { + #[allow(dead_code)] pub process: MongoProcess, #[allow(dead_code)] pub embedded: MongoEmbedded, @@ -89,6 +91,7 @@ pub(crate) struct MongoParts { pub(crate) struct TestMongoHelper { pub store: Arc, pub database_name: String, + #[allow(dead_code)] pub mongo_local: Option, pub spec: ExperimentalMongoSpec, } @@ -102,17 +105,20 @@ impl TestMongoHelper { let test_mongo_url = if let Ok(url) = std::env::var("NATIVELINK_TEST_MONGO_URL") { url } else { - let port = redis_test::utils::get_random_available_port(); - let mongo_runner = MongoEmbedded::new("7.0.11").set_port(port); + let mongo_runner = MongoEmbedded::new("7.0.11"); let process = mongo_runner .start() .await .err_tip(|| "Failed to start MongoDB")?; + // The runner picks its own free port (and re-picks it if it loses + // a bind race), so use the connection string it reports rather + // than assuming a port chosen up front is still free. + let url = process.connection_string.clone(); mongo_local.replace(MongoParts { process, embedded: mongo_runner, }); - format!("mongodb://127.0.0.1:{port}/") + url }; let spec = create_test_spec_with_key_prefix(key_prefix, test_mongo_url); @@ -145,14 +151,14 @@ impl TestMongoHelper { impl Drop for TestMongoHelper { fn drop(&mut self) { - // No longer cleaning up databases - we want to keep them for inspection + // No longer cleaning up databases - we want to keep them for inspection. + // Dropping mongo_local kills the mongod; that path must never panic, + // because Drop also runs while unwinding from a failed assertion and a + // double panic would abort the whole test binary. eprintln!( "Test database '{}' retained for inspection", self.database_name ); - if let Some(mut parts) = self.mongo_local.take() { - parts.process.kill().expect("Failed to kill mongo process"); - } } } @@ -585,8 +591,8 @@ async fn create_ten_cas_entries() -> Result<(), Error> { eprintln!("Successfully created CAS entry #{i} with digest: {digest}"); } - // Query MongoDB directly to verify entries were written - let helper = TestMongoHelper::new(None).await?; + // Query MongoDB directly (same instance and database the store wrote to) + // to verify entries were written. let client_options = ClientOptions::parse(&helper.spec.connection_string) .await .map_err(|e| make_err!(Code::Internal, "Failed to parse connection string: {e}"))?; @@ -604,6 +610,7 @@ async fn create_ten_cas_entries() -> Result<(), Error> { .map_err(|e| make_err!(Code::Internal, "Failed to count documents: {e}"))?; eprintln!("Total documents in CAS collection: {count}"); + assert_eq!(count, 10, "Expected one document per uploaded CAS entry"); // List first few documents let mut cursor = collection diff --git a/nativelink-store/tests/oci_store_test.rs b/nativelink-store/tests/oci_store_test.rs new file mode 100644 index 000000000..d2eb5cadb --- /dev/null +++ b/nativelink-store/tests/oci_store_test.rs @@ -0,0 +1,272 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! `OciStore` builds an SDK client and hands it to `S3Store`. These tests cover +//! the config -> client mapping and the OCI-specific wire behavior (path-style +//! URLs and non-`aws-chunked` uploads) using a `StaticReplayClient`, all without +//! a live bucket. The generic S3 wire behavior is covered by `s3_store_test.rs`; +//! live round-trip / multipart / load coverage is kept out of the repo. + +use std::sync::Arc; + +use aws_smithy_http_client::test_util::{ReplayEvent, StaticReplayClient}; +use aws_smithy_types::body::SdkBody; +use http::{StatusCode, header}; +use nativelink_config::stores::{CommonObjectSpec, ExperimentalOciSpec}; +use nativelink_error::{Code, Error}; +use nativelink_macro::nativelink_test; +use nativelink_store::oci_store::OciStore; +use nativelink_store::s3_store::S3Store; +use nativelink_util::common::DigestInfo; +use nativelink_util::instant_wrapper::MockInstantWrapped; +use nativelink_util::store_trait::StoreLike; +use pretty_assertions::assert_eq; + +#[nativelink_test] +async fn endpoint_is_derived_from_namespace_and_region() -> Result<(), Error> { + let endpoint = OciStore::derive_endpoint(&ExperimentalOciSpec { + namespace: "axaxnpcrorw5".to_string(), + region: "us-phoenix-1".to_string(), + bucket: "ignored".to_string(), + ..Default::default() + }); + assert_eq!( + endpoint, + "https://axaxnpcrorw5.compat.objectstorage.us-phoenix-1.oci.customer-oci.com", + ); + Ok(()) +} + +#[nativelink_test] +async fn aws_spec_passes_region_bucket_and_common_through() -> Result<(), Error> { + let aws_spec = OciStore::build_aws_spec(&ExperimentalOciSpec { + namespace: "ignored".to_string(), + region: "us-ashburn-1".to_string(), + bucket: "test-bucket".to_string(), + common: CommonObjectSpec { + key_prefix: Some("cas/".to_string()), + consider_expired_after_s: 86400, + ..Default::default() + }, + ..Default::default() + }); + // The OCI region is forwarded verbatim so it is used as the SigV4 signing + // region (unlike R2, which always signs against `auto`). + assert_eq!(aws_spec.region, "us-ashburn-1"); + assert_eq!(aws_spec.bucket, "test-bucket"); + assert_eq!(aws_spec.common.key_prefix.as_deref(), Some("cas/")); + assert_eq!(aws_spec.common.consider_expired_after_s, 86400); + Ok(()) +} + +// --------------------------------------------------------------------------- +// Mock wire-behavior tests. Drive the store through `new_with_http_client` with +// a `StaticReplayClient` to verify the OCI-specific request shaping without a +// live bucket. +// --------------------------------------------------------------------------- + +const NAMESPACE: &str = "ns"; +const REGION: &str = "us-region-1"; +const BUCKET: &str = "test-bucket"; +const HOST: &str = "ns.compat.objectstorage.us-region-1.oci.customer-oci.com"; +const VALID_HASH1: &str = "0123456789abcdef000000000000000000010000000000000123456789abcdef"; + +// Coerces the function item to a plain fn pointer matching the store type. +const NOW_FN: fn() -> MockInstantWrapped = MockInstantWrapped::default; + +fn mock_spec() -> ExperimentalOciSpec { + ExperimentalOciSpec { + namespace: NAMESPACE.to_string(), + region: REGION.to_string(), + bucket: BUCKET.to_string(), + access_key_id: Some("AKIDTEST".to_string()), + secret_access_key: Some("SECRETTEST".to_string()), + ..Default::default() + } +} + +async fn store_with( + mock: StaticReplayClient, +) -> Result MockInstantWrapped>>, Error> { + OciStore::new_with_http_client(&mock_spec(), mock, NOW_FN).await +} + +#[nativelink_test] +async fn has_object_found_uses_path_style_endpoint() -> Result<(), Error> { + const SIZE: u64 = 512; + let mock = StaticReplayClient::new(vec![ReplayEvent::new( + http::Request::builder() + .method("HEAD") + .uri(format!("https://{HOST}/{BUCKET}/{VALID_HASH1}-{SIZE}")) + .body(SdkBody::empty()) + .unwrap(), + http::Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_LENGTH, SIZE.to_string()) + .body(SdkBody::empty()) + .unwrap(), + )]); + let store = store_with(mock.clone()).await?; + + let result = store.has(DigestInfo::try_new(VALID_HASH1, SIZE)?).await?; + assert_eq!(result, Some(SIZE), "expected object to be found"); + mock.assert_requests_match(&[]); + Ok(()) +} + +#[nativelink_test] +async fn has_object_not_found_returns_none() -> Result<(), Error> { + let mock = StaticReplayClient::new(vec![ReplayEvent::new( + http::Request::builder().body(SdkBody::empty()).unwrap(), + http::Response::builder() + .status(StatusCode::NOT_FOUND) + .body(SdkBody::empty()) + .unwrap(), + )]); + let store = store_with(mock).await?; + + let result = store.has(DigestInfo::try_new(VALID_HASH1, 100)?).await?; + assert_eq!(result, None, "expected absent object to map to None"); + Ok(()) +} + +#[nativelink_test] +async fn get_missing_object_maps_to_not_found() -> Result<(), Error> { + // OCI (like S3) returns a NoSuchKey error document on a missing GET; the SDK + // parses it and the store maps it to `Code::NotFound`. + const NO_SUCH_KEY: &str = concat!( + "", + "NoSuchKey", + "The specified key does not exist." + ); + let mock = StaticReplayClient::new(vec![ReplayEvent::new( + http::Request::builder().body(SdkBody::empty()).unwrap(), + http::Response::builder() + .status(StatusCode::NOT_FOUND) + .body(SdkBody::from(NO_SUCH_KEY)) + .unwrap(), + )]); + let store = store_with(mock).await?; + + let err = store + .get_part_unchunked(DigestInfo::try_new(VALID_HASH1, 100)?, 0, None) + .await + .expect_err("get on a missing object must error"); + assert_eq!( + err.code, + Code::NotFound, + "expected NotFound code for an absent object" + ); + Ok(()) +} + +#[nativelink_test] +async fn update_single_put_is_path_style_and_unchunked() -> Result<(), Error> { + const DATA: &[u8] = b"hello-oci-single-put-body"; + let mock = StaticReplayClient::new(vec![ReplayEvent::new( + http::Request::builder().body(SdkBody::empty()).unwrap(), + http::Response::builder() + .status(StatusCode::OK) + .body(SdkBody::empty()) + .unwrap(), + )]); + let store = store_with(mock.clone()).await?; + + store + .update_oneshot( + DigestInfo::try_new(VALID_HASH1, DATA.len() as u64)?, + DATA.into(), + ) + .await?; + + let reqs: Vec<_> = mock.actual_requests().collect(); + assert_eq!(reqs.len(), 1, "expected exactly one PutObject request"); + let req = &reqs[0]; + assert_eq!(req.method(), "PUT", "single-shot upload should be a PUT"); + let want_prefix = format!("https://{HOST}/{BUCKET}/{VALID_HASH1}-{}", DATA.len()); + assert!( + req.uri().starts_with(&want_prefix), + "expected path-style URL starting with {want_prefix}, got {}", + req.uri() + ); + let sha = req + .headers() + .get("x-amz-content-sha256") + .unwrap_or_default(); + assert!( + !sha.contains("STREAMING") && !sha.contains("CHUNKED"), + "PutObject must not use aws-chunked payload signing, got x-amz-content-sha256={sha}" + ); + assert_ne!( + req.headers().get("content-encoding"), + Some("aws-chunked"), + "PutObject must not set Content-Encoding: aws-chunked" + ); + Ok(()) +} + +#[nativelink_test] +async fn get_object_returns_bytes() -> Result<(), Error> { + const VALUE: &str = "oci-object-contents"; + let mock = StaticReplayClient::new(vec![ReplayEvent::new( + http::Request::builder() + .uri(format!( + "https://{HOST}/{BUCKET}/{VALID_HASH1}-1000?x-id=GetObject" + )) + .body(SdkBody::empty()) + .unwrap(), + http::Response::builder() + .status(StatusCode::OK) + .body(SdkBody::from(VALUE)) + .unwrap(), + )]); + let store = store_with(mock.clone()).await?; + + let got = store + .get_part_unchunked(DigestInfo::try_new(VALID_HASH1, 1000)?, 0, None) + .await?; + assert_eq!(got, VALUE.as_bytes()); + mock.assert_requests_match(&[]); + Ok(()) +} + +#[nativelink_test] +async fn ranged_get_sends_range_header_path_style() -> Result<(), Error> { + const OFFSET: usize = 105; + const LENGTH: usize = 50_000; + let mock = StaticReplayClient::new(vec![ReplayEvent::new( + http::Request::builder() + .uri(format!( + "https://{HOST}/{BUCKET}/{VALID_HASH1}-1000?x-id=GetObject" + )) + .header("range", format!("bytes={OFFSET}-{}", OFFSET + LENGTH)) + .body(SdkBody::empty()) + .unwrap(), + http::Response::builder() + .status(StatusCode::OK) + .body(SdkBody::empty()) + .unwrap(), + )]); + let store = store_with(mock.clone()).await?; + + store + .get_part_unchunked( + DigestInfo::try_new(VALID_HASH1, 1000)?, + OFFSET as u64, + Some(LENGTH as u64), + ) + .await?; + mock.assert_requests_match(&[]); + Ok(()) +} diff --git a/nativelink-store/tests/redis_store_test.rs b/nativelink-store/tests/redis_store_test.rs index d58340bfd..f93d0bbeb 100644 --- a/nativelink-store/tests/redis_store_test.rs +++ b/nativelink-store/tests/redis_store_test.rs @@ -13,13 +13,14 @@ // limitations under the License. use core::ops::RangeBounds; +use core::pin::Pin; use core::time::Duration; use std::collections::HashMap; use std::sync::Arc; use bytes::{Bytes, BytesMut}; use futures::TryStreamExt; -use nativelink_config::stores::{RedisMode, RedisSpec}; +use nativelink_config::stores::{ExistenceCacheSpec, RedisMode, RedisSpec, StoreSpec}; use nativelink_error::{Code, Error, ErrorContext, ResultExt, make_err}; use nativelink_macro::nativelink_test; use nativelink_redis_tester::{ @@ -28,22 +29,24 @@ use nativelink_redis_tester::{ make_fake_redis_with_responses, }; use nativelink_store::cas_utils::ZERO_BYTE_DIGESTS; +use nativelink_store::existence_cache_store::ExistenceCacheStore; use nativelink_store::redis_store::{ ClusterRedisManager, DEFAULT_MAX_CHUNK_UPLOADS_PER_UPDATE, DEFAULT_MAX_COUNT_PER_CURSOR, - LUA_VERSION_SET_SCRIPT, RedisStore, RedisSubscriptionManager, + LUA_VERSION_SET_SCRIPT, RedisStore, RedisSubscriptionManager, decode_key, }; use nativelink_util::buf_channel::make_buf_channel_pair; use nativelink_util::common::DigestInfo; use nativelink_util::health_utils::HealthStatus; use nativelink_util::store_trait::{ - FalseValue, SchedulerCurrentVersionProvider, SchedulerIndexProvider, SchedulerStore, - SchedulerStoreDataProvider, SchedulerStoreDecodeTo, SchedulerStoreKeyProvider, - SchedulerSubscription, SchedulerSubscriptionManager, StoreKey, StoreLike, TrueValue, - UploadSizeInfo, + FalseValue, RemoveItemCallback, SchedulerCurrentVersionProvider, SchedulerIndexProvider, + SchedulerStore, SchedulerStoreDataProvider, SchedulerStoreDecodeTo, SchedulerStoreKeyProvider, + SchedulerSubscription, SchedulerSubscriptionManager, Store, StoreDriver, StoreKey, StoreLike, + TrueValue, UploadSizeInfo, }; use pretty_assertions::assert_eq; use redis::{PushInfo, RedisError, Value, make_extension_error}; use redis_test::{MockCmd, MockRedisConnection}; +use tokio::sync::mpsc::UnboundedReceiver; use tokio::time::{sleep, timeout}; use tracing::{Instrument, info, info_span}; @@ -84,9 +87,11 @@ async fn fake_redis_sentinel_master_stream_with_script() -> u16 { .await } -async fn make_mock_store_with_prefix( +async fn make_mock_store_with_prefix_and_subscriber_channel( mut commands: Vec, key_prefix: String, + key_ttl: Option, + subscriber_channel: UnboundedReceiver, ) -> RedisStore> { commands.insert( 0, @@ -97,7 +102,6 @@ async fn make_mock_store_with_prefix( ); let mock_connection = MockRedisConnection::new(commands); let manager = ClusterRedisManager::new(mock_connection).await.unwrap(); - let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); RedisStore::new_from_builder_and_parts( None, mock_uuid_generator, @@ -108,13 +112,31 @@ async fn make_mock_store_with_prefix( DEFAULT_MAX_PERMITS, DEFAULT_MAX_COUNT_PER_CURSOR, Duration::from_secs(4), - rx, + key_ttl, + subscriber_channel, manager, ) .await .unwrap() } +async fn make_mock_store_with_ttl( + commands: Vec, + key_ttl: Duration, +) -> RedisStore> { + let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); + make_mock_store_with_prefix_and_subscriber_channel(commands, String::new(), Some(key_ttl), rx) + .await +} + +async fn make_mock_store_with_prefix( + commands: Vec, + key_prefix: String, +) -> RedisStore> { + let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); + make_mock_store_with_prefix_and_subscriber_channel(commands, key_prefix, None, rx).await +} + #[nativelink_test] async fn upload_and_get_data() -> Result<(), Error> { // Construct the data we want to send. Since it's small, we expect it to be sent in a single chunk. @@ -133,20 +155,18 @@ async fn upload_and_get_data() -> Result<(), Error> { // Append the real value to the temp key. MockCmd::new( redis::cmd("SETRANGE") - .arg(temp_key.clone()) + .arg(&temp_key) .arg(0) .arg(data.to_vec()), Ok(Value::Int(0)), ), MockCmd::new( - redis::cmd("STRLEN").arg(temp_key.clone()), - Ok(Value::Int(data.len() as i64)), + redis::cmd("STRLEN").arg(&temp_key), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), ), // Move the data from the fake key to the real key. MockCmd::new( - redis::cmd("RENAME") - .arg(temp_key.clone()) - .arg(real_key.clone()), + redis::cmd("RENAME").arg(&temp_key).arg(&real_key), Ok(Value::Nil), ), // The second set of commands are for retrieving the data from the key. @@ -154,9 +174,9 @@ async fn upload_and_get_data() -> Result<(), Error> { MockCmd::with_values( redis::pipe() .cmd("STRLEN") - .arg(real_key.clone()) + .arg(&real_key) .cmd("EXISTS") - .arg(real_key.clone()), + .arg(&real_key), Ok(vec![Value::Int(2), Value::Boolean(true)]), ), // Retrieve the data from the real key. @@ -215,7 +235,7 @@ async fn update_retries_after_transient_zero_length() -> Result<(), Error> { // After re-resolving the master, the retry sees the real length. MockCmd::new( redis::cmd("STRLEN").arg(temp_key.clone()), - Ok(Value::Int(data.len() as i64)), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), ), MockCmd::new( redis::cmd("RENAME").arg(temp_key).arg(real_key), @@ -339,7 +359,7 @@ async fn update_retries_after_transient_write_error() -> Result<(), Error> { ), MockCmd::new( redis::cmd("STRLEN").arg(temp_key.clone()), - Ok(Value::Int(data.len() as i64)), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), ), MockCmd::new( redis::cmd("RENAME").arg(temp_key).arg(real_key), @@ -375,7 +395,7 @@ async fn upload_and_get_data_with_prefix() -> Result<(), Error> { ), MockCmd::new( redis::cmd("STRLEN").arg(temp_key.clone()), - Ok(Value::Int(data.len() as i64)), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), ), MockCmd::new( redis::cmd("RENAME").arg(temp_key).arg(real_key.clone()), @@ -473,7 +493,7 @@ async fn test_large_downloads_are_chunked() -> Result<(), Error> { ), MockCmd::new( redis::cmd("STRLEN").arg(temp_key.clone()), - Ok(Value::Int(data.len() as i64)), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), ), MockCmd::new( redis::cmd("RENAME").arg(temp_key).arg(real_key.clone()), @@ -496,15 +516,15 @@ async fn test_large_downloads_are_chunked() -> Result<(), Error> { redis::cmd("GETRANGE") .arg(real_key.clone()) .arg(0) - .arg(READ_CHUNK_SIZE as i64 - 1), + .arg(READ_CHUNK_SIZE.try_into().unwrap_or(i64::MAX) - 1), Ok(Value::BulkString(data.slice(..READ_CHUNK_SIZE).into())), ), MockCmd::new( // Similar GETRANGE index shenanigans here. redis::cmd("GETRANGE") .arg(real_key) - .arg(READ_CHUNK_SIZE as i64) - .arg(data.len() as i64 - 1), + .arg(READ_CHUNK_SIZE.try_into().unwrap_or(i64::MAX)) + .arg(data.len().try_into().unwrap_or(i64::MAX) - 1), Ok(Value::BulkString(data.slice(READ_CHUNK_SIZE..).into())), ), ]; @@ -566,7 +586,7 @@ async fn yield_between_sending_packets_in_update() -> Result<(), Error> { ), MockCmd::new( redis::cmd("STRLEN").arg(temp_key.clone()), - Ok(Value::Int(data.len() as i64)), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), ), MockCmd::new( redis::cmd("RENAME").arg(temp_key).arg(real_key.clone()), @@ -584,21 +604,29 @@ async fn yield_between_sending_packets_in_update() -> Result<(), Error> { redis::cmd("GETRANGE") .arg(real_key.clone()) .arg(0) - .arg((DEFAULT_READ_CHUNK_SIZE - 1) as i64), + .arg((DEFAULT_READ_CHUNK_SIZE - 1).try_into().unwrap_or(i64::MAX)), Ok(Value::BulkString(data.clone().to_vec())), ), MockCmd::new( redis::cmd("GETRANGE") .arg(real_key.clone()) - .arg(DEFAULT_READ_CHUNK_SIZE as i64) - .arg((DEFAULT_READ_CHUNK_SIZE * 2 - 1) as i64), + .arg(DEFAULT_READ_CHUNK_SIZE.try_into().unwrap_or(i64::MAX)) + .arg( + (DEFAULT_READ_CHUNK_SIZE * 2 - 1) + .try_into() + .unwrap_or(i64::MAX), + ), Ok(Value::BulkString(data.clone().to_vec())), ), MockCmd::new( redis::cmd("GETRANGE") .arg(real_key) - .arg((DEFAULT_READ_CHUNK_SIZE * 2) as i64) - .arg((data_p1.len() + data_p2.len() - 1) as i64), + .arg((DEFAULT_READ_CHUNK_SIZE * 2).try_into().unwrap_or(i64::MAX)) + .arg( + (data_p1.len() + data_p2.len() - 1) + .try_into() + .unwrap_or(i64::MAX), + ), Ok(Value::BulkString(data.clone().to_vec())), ), ]; @@ -653,7 +681,7 @@ async fn zero_len_items_exist_check() -> Result<(), Error> { redis::cmd("GETRANGE") .arg(real_key.clone()) .arg(0) - .arg(DEFAULT_READ_CHUNK_SIZE as i64 - 1), + .arg(DEFAULT_READ_CHUNK_SIZE.try_into().unwrap_or(i64::MAX) - 1), Ok(Value::BulkString(vec![])), ), MockCmd::new(redis::cmd("EXISTS").arg(real_key), Ok(Value::Int(0))), @@ -941,9 +969,14 @@ async fn test_sentinel_connect_with_bad_master() { connection_timeout_ms: 100, ..Default::default() }; + // Unavailable, not InvalidArgument: an unknown master name is + // indistinguishable from a sentinel failover in progress, and the two + // must not be told apart by guessing. A genuinely wrong name keeps + // failing and stays visible; a failover recovers on retry. Classifying + // this as permanent meant a routine failover killed in-flight builds. assert_eq!( Error { - code: Code::InvalidArgument, + code: Code::Unavailable, messages: vec![ "MasterNameNotFoundBySentinel: Master with given name not found in sentinel - MasterNameNotFoundBySentinel".into(), format!("While connecting to redis with url: redis+sentinel://127.0.0.1:{port}/") @@ -1004,7 +1037,7 @@ async fn test_sentinel_connect_and_update_data_unversioned_readonly() { version: 0, }; store - .update_data(data, Some(Duration::from_secs(60))) + .update_data(data, Some(Duration::from_mins(1))) .await .expect("working update"); } @@ -1050,7 +1083,13 @@ async fn test_sentinel_connect_with_url_specified_master() { "redis+sentinel://127.0.0.1:{port}/?sentinelServiceName=specific_master" )], mode: RedisMode::Sentinel, - connection_timeout_ms: 100, + // This test asserts that the sentinelServiceName URL parameter + // resolves, not that it resolves quickly. 100ms — copied from the + // fail-fast bad-master test above, where a tight budget is the point — + // has to cover two TCP connects and two handshakes plus SENTINEL + // MASTERS in between, which a loaded macOS CI runner does not manage. + // Every other success-path test here allows 1s or more. + connection_timeout_ms: 5_000, ..Default::default() }; RedisStore::new_standard(spec).await.expect("Working spec"); @@ -1392,6 +1431,126 @@ fn test_search_by_index_retries_on_failover() -> Result<(), Error> { Ok(()) } +/// `RediSearch` matches documents in the search phase and reads their fields +/// in the load phase. A document that expires or is deleted between the two +/// comes back as a RESP3 row whose `extra_attributes` is Nil. That is routine +/// on a busy scheduler — completed awaited-action records expire constantly — +/// so the row must drop out of the results rather than fail the whole +/// aggregate. Failing it reached clients as `INVALID_ARGUMENT`, which Bazel +/// treats as permanent, so one expiry race ended the build. +#[nativelink_test] +fn test_search_by_index_skips_docs_that_expired_mid_query() -> Result<(), Error> { + fn loaded_row(content: &str) -> Value { + Value::Map(vec![ + ( + Value::SimpleString("extra_attributes".into()), + Value::Map(vec![ + ( + Value::BulkString(b"data".to_vec()), + Value::BulkString(content.as_bytes().to_vec()), + ), + ( + Value::BulkString(b"version".to_vec()), + Value::BulkString(b"1".to_vec()), + ), + ]), + ), + (Value::SimpleString("values".into()), Value::Array(vec![])), + ]) + } + + fn expired_row() -> Value { + Value::Map(vec![ + (Value::SimpleString("extra_attributes".into()), Value::Nil), + (Value::SimpleString("values".into()), Value::Array(vec![])), + ]) + } + + fn make_ft_aggregate() -> MockCmd { + MockCmd::new( + redis::cmd("FT.AGGREGATE") + .arg("test:_content_prefix_sort_key_3e762c15") + .arg("@content_prefix:{ Searchable }") + .arg("TIMEOUT") + .arg(10000_u64) + .arg("LOAD") + .arg(2) + .arg("data") + .arg("version") + .arg("WITHCURSOR") + .arg("COUNT") + .arg(1500) + .arg("MAXIDLE") + .arg(30000) + .arg("SORTBY") + .arg(2usize) + .arg("@sort_key") + .arg("ASC"), + // A page whose middle document expired between match and load. + Ok(Value::Array(vec![ + Value::Map(vec![ + ( + Value::SimpleString("attributes".into()), + Value::Array(vec![]), + ), + ( + Value::SimpleString("format".into()), + Value::SimpleString("STRING".into()), + ), + ( + Value::SimpleString("results".into()), + Value::Array(vec![loaded_row("1234"), expired_row(), loaded_row("5678")]), + ), + ]), + Value::Int(0), + ])), + ) + } + + let commands = vec![ + make_ft_aggregate(), + MockCmd::new( + redis::cmd("FT.CREATE") + .arg("test:_content_prefix__3e762c15") + .arg("ON") + .arg("HASH") + .arg("NOHL") + .arg("NOFIELDS") + .arg("NOFREQS") + .arg("NOOFFSETS") + .arg("TEMPORARY") + .arg(86400) + .arg("PREFIX") + .arg(1) + .arg("test:") + .arg("SCHEMA") + .arg("content_prefix") + .arg("TAG"), + Ok(Value::Nil), + ), + make_ft_aggregate(), + ]; + let store = make_mock_store(commands).await; + let search_provider = SearchByContentPrefix { + prefix: "Searchable".to_string(), + }; + + let search_results: Vec = store + .search_by_index_prefix(search_provider) + .await + .err_tip(|| "The expired row must not fail the aggregate")? + .try_collect() + .await?; + + // Only the two surviving documents come back; the expired one contributes + // nothing rather than taking the other two down with it. + assert_eq!(search_results.len(), 2, "Should skip only the expired row"); + assert_eq!(search_results[0].content, "1234"); + assert_eq!(search_results[1].content, "5678"); + + Ok(()) +} + #[nativelink_test] fn test_search_by_index_failure() -> Result<(), Error> { let store = make_mock_store(vec![]).await; @@ -1863,7 +2022,8 @@ fn test_search_by_index_skips_int_from_cursor_read() -> Result<(), Error> { #[nativelink_test] async fn no_items_from_none_subscription_channel() -> Result<(), Error> { let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let subscription_manager = RedisSubscriptionManager::new(rx); + let subscription_manager = + RedisSubscriptionManager::new(rx, Arc::new(async_lock::Mutex::new(vec![])), String::new()); // To give the stream enough time to get polled sleep(Duration::from_secs(1)).await; @@ -1882,7 +2042,8 @@ async fn no_items_from_none_subscription_channel() -> Result<(), Error> { #[nativelink_test] async fn send_messages_to_subscription_channel() -> Result<(), Error> { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let subscription_manager = RedisSubscriptionManager::new(rx); + let subscription_manager = + RedisSubscriptionManager::new(rx, Arc::new(async_lock::Mutex::new(vec![])), String::new()); tx.send(PushInfo { kind: redis::PushKind::PSubscribe, @@ -1922,6 +2083,10 @@ async fn send_messages_to_subscription_channel() -> Result<(), Error> { // Because otherwise it gets dropped immediately, and we need it to live to do things drop(subscription_manager); + assert!(logs_contain( + "PSubscribe, ignore push_info=PushInfo { kind: PSubscribe, data: [bulk-string('\"scheduler_key_change\"'), int(1)] }" + )); + Ok(()) } @@ -1964,7 +2129,7 @@ async fn core_test_update_data_unversioned_with_expiry(expire_response: i64) { version: 0, }; store - .update_data(data, Some(Duration::from_secs(60))) + .update_data(data, Some(Duration::from_mins(1))) .await .expect("working update"); } @@ -2019,7 +2184,7 @@ async fn test_update_data_versioned_with_expiry() { version: 0, }; store - .update_data(data, Some(Duration::from_secs(60))) + .update_data(data, Some(Duration::from_mins(1))) .await .expect("working update"); } @@ -2041,7 +2206,8 @@ impl SchedulerStoreKeyProvider for TestSubKey { #[nativelink_test] async fn redis_subscription_single_drop_is_silent() -> Result<(), Error> { let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let manager = RedisSubscriptionManager::new(rx); + let manager = + RedisSubscriptionManager::new(rx, Arc::new(async_lock::Mutex::new(vec![])), String::new()); let sub = manager.subscribe(TestSubKey("solo-key".to_string()))?; drop(sub); @@ -2060,7 +2226,8 @@ async fn redis_subscription_single_drop_is_silent() -> Result<(), Error> { #[nativelink_test] async fn redis_subscription_drop_one_of_two_keeps_publisher() -> Result<(), Error> { let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let manager = RedisSubscriptionManager::new(rx); + let manager = + RedisSubscriptionManager::new(rx, Arc::new(async_lock::Mutex::new(vec![])), String::new()); let key = "shared-key"; let sub_a = manager.subscribe(TestSubKey(key.to_string()))?; @@ -2088,7 +2255,8 @@ async fn redis_subscription_drop_one_of_two_keeps_publisher() -> Result<(), Erro async fn redis_subscription_concurrent_drops_no_absence_warn() -> Result<(), Error> { const ITERATIONS: usize = 200; let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let manager = RedisSubscriptionManager::new(rx); + let manager = + RedisSubscriptionManager::new(rx, Arc::new(async_lock::Mutex::new(vec![])), String::new()); for i in 0..ITERATIONS { let key = format!("race-key-{i}"); @@ -2122,7 +2290,8 @@ async fn redis_subscription_concurrent_drops_no_absence_warn() -> Result<(), Err #[nativelink_test] async fn redis_subscription_resubscribe_after_drop_creates_fresh_publisher() -> Result<(), Error> { let (_tx, rx) = tokio::sync::mpsc::unbounded_channel(); - let manager = RedisSubscriptionManager::new(rx); + let manager = + RedisSubscriptionManager::new(rx, Arc::new(async_lock::Mutex::new(vec![])), String::new()); let key = "cycle-key"; let sub_a = manager.subscribe(TestSubKey(key.to_string()))?; @@ -2148,3 +2317,465 @@ async fn redis_subscription_resubscribe_after_drop_creates_fresh_publisher() -> drop(manager); Ok(()) } + +#[derive(Debug)] +struct LoggingRemoveCallback {} + +impl RemoveItemCallback for LoggingRemoveCallback { + fn callback<'a>( + &'a self, + store_key: StoreKey<'a>, + ) -> Pin + Send + 'a>> { + info!(?store_key, "Callback for removed item"); + Box::pin(async {}) + } +} + +async fn callback_for_eviction_core( + logs_contain: F, + notify_keyspace_events: &[u8], +) -> Result<(), Error> +where + F: Fn(&str) -> bool, +{ + let redis_span = info_span!("redis"); + + let mut responses = add_lua_version_script(fake_redis_stream()); + add_to_response( + &mut responses, + redis::cmd("CONFIG") + .arg("GET") + .arg("notify-keyspace-events"), + vec![Value::Map(vec![( + Value::BulkString(b"notify-keyspace-events".into()), + Value::BulkString(notify_keyspace_events.into()), + )])], + ); + add_to_response( + &mut responses, + redis::cmd("PSUBSCRIBE").arg("__key*__:*"), + vec![Value::Nil], + ); + let redis_port = make_fake_redis_with_responses(responses) + .instrument(redis_span) + .await; + let spec = RedisSpec { + addresses: vec![format!("redis://127.0.0.1:{redis_port}/")], + mode: RedisMode::Standard, + ..Default::default() + }; + let mut raw_store = + Arc::into_inner(RedisStore::new_standard(spec).await.expect("Working spec")).unwrap(); + raw_store.replace_temp_name_generator(mock_uuid_generator); + let store = Arc::new(raw_store); + store.register_remove_callback(Arc::new(LoggingRemoveCallback {}))?; + + timeout(Duration::from_secs(3), async move { + loop { + if logs_contain("new psubscribe complete pattern=\"__key*__:*\" new_subscription=true") + { + break; + } + sleep(Duration::from_millis(100)).await; + } + }) + .await?; + Ok(()) +} + +#[nativelink_test] +async fn callback_for_eviction_not_enabled() -> Result<(), Error> { + callback_for_eviction_core(logs_contain, b"").await?; + assert!(logs_contain( + "notify-keyspace-events not enabled for Redis, will fail to get remove callbacks" + )); + Ok(()) +} + +#[nativelink_test] +async fn callback_for_eviction_no_keyspace() -> Result<(), Error> { + callback_for_eviction_core(logs_contain, b"E").await?; + assert!(logs_contain( + "notify-keyspace-events does not contain 'K' so won't get keyspace events we need for eviction events notify_keyspace_events=\"E\"" + )); + Ok(()) +} + +#[nativelink_test] +async fn callback_for_eviction_no_all() -> Result<(), Error> { + callback_for_eviction_core(logs_contain, b"K").await?; + assert!(logs_contain( + "notify-keyspace-events does not contain 'A' so we won't get eviction events notify_keyspace_events=\"K\"" + )); + Ok(()) +} + +#[nativelink_test] +async fn callback_for_eviction_good() -> Result<(), Error> { + callback_for_eviction_core(logs_contain, b"KA").await?; + assert!(!logs_contain("ERROR")); + Ok(()) +} + +#[nativelink_test] +async fn send_eviction_to_subscription_channel() -> Result<(), Error> { + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + let subscription_manager = RedisSubscriptionManager::new( + rx, + Arc::new(async_lock::Mutex::new(vec![Arc::new( + LoggingRemoveCallback {}, + )])), + String::new(), + ); + + tx.send(PushInfo { + kind: redis::PushKind::PMessage, + data: vec![ + Value::BulkString("demo_pattern".into()), + Value::BulkString("keyprefix:test-eviction".into()), + Value::BulkString("evicted".into()), + ], + }) + .unwrap(); + + timeout(Duration::from_secs(5), async { + loop { + assert!(!logs_contain("ERROR")); + if logs_contain("Callback for removed item store_key=Str(\"test-eviction\")") { + break; + } + sleep(Duration::from_millis(100)).await; + } + }) + .await + .unwrap(); + + // Because otherwise it gets dropped immediately, and we need it to live to do things + drop(subscription_manager); + + assert!(logs_contain( + "Removed key removed_key=\"keyprefix:test-eviction\"" + )); + + Ok(()) +} + +async fn store_key_coding_round_trip_core(key_prefix: String) -> Result<(), Error> { + let store = make_mock_store_with_prefix(vec![], key_prefix.clone()).await; + + for key in [ + StoreKey::new_str("foo"), + StoreKey::Digest(DigestInfo::zero_digest()), + StoreKey::Digest(DigestInfo::new([99u8; 32], 512)), + ] { + assert_eq!(key, decode_key(&key_prefix, store.encode_key(&key))?); + } + Ok(()) +} + +#[nativelink_test] +async fn store_key_coding_round_trip() -> Result<(), Error> { + store_key_coding_round_trip_core(String::new()).await +} + +#[nativelink_test] +async fn store_key_coding_round_trip_with_prefix() -> Result<(), Error> { + store_key_coding_round_trip_core(String::from("demo")).await +} + +async fn evict_keys_for_existence_cache_core( + prefix: String, + removal_event: &str, + logs_contain: F, +) -> Result<(), Error> +where + F: Fn(&str) -> bool + Send + Sync, +{ + let spec = ExistenceCacheSpec { + backend: StoreSpec::RedisStore(RedisSpec::default()), // Note: Not used. + eviction_policy: Option::default(), // Not evicting here, we'll evict from Redis + }; + let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); + + let data = Bytes::from_static(b"14"); + let digest = DigestInfo::try_new(VALID_HASH1, 2)?; + let real_key = format!("{prefix}{digest}"); + let temp_key = make_temp_key(&real_key); + + let commands = vec![ + MockCmd::new( + redis::cmd("CONFIG") + .arg("GET") + .arg("notify-keyspace-events"), + Ok(Value::Map(vec![( + Value::BulkString(b"notify-keyspace-events".into()), + Value::BulkString(b"KA".into()), + )])), + ), + MockCmd::with_values( + redis::pipe() + .cmd("STRLEN") + .arg(&real_key) + .cmd("EXISTS") + .arg(&real_key), + Ok(vec![Value::Int(2), Value::Boolean(true)]), + ), + MockCmd::new( + redis::cmd("SETRANGE") + .arg(&temp_key) + .arg(0) + .arg(data.to_vec()), + Ok(Value::Int(0)), + ), + MockCmd::new( + redis::cmd("STRLEN").arg(&temp_key), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), + ), + // Move the data from the fake key to the real key. + MockCmd::new( + redis::cmd("RENAME").arg(&temp_key).arg(&real_key), + Ok(Value::Nil), + ), + // Retrieve the data from the real key. + MockCmd::new( + redis::cmd("GETRANGE").arg(&real_key).arg(0).arg(1), + Ok(Value::BulkString(b"14".to_vec())), + ), + ]; + + let redis_store = Arc::new( + make_mock_store_with_prefix_and_subscriber_channel(commands, prefix.clone(), None, rx) + .await, + ); + let existence_store = ExistenceCacheStore::new(&spec, Store::new(redis_store.clone())); + + // Wait for subscription first so the mock redis commands are in the right order + timeout(Duration::from_secs(5), async { + loop { + assert!(!logs_contain("ERROR")); + if logs_contain("Attempting to subscribe to eviction events") { + break; + } + sleep(Duration::from_millis(100)).await; + } + }) + .await + .unwrap(); + + existence_store + .update_oneshot(digest, data.clone()) + .await + .unwrap(); + + tx.send(PushInfo { + kind: redis::PushKind::PMessage, + data: vec![ + Value::BulkString("demo_pattern".into()), + Value::BulkString(format!("keyprefix:{real_key}").into()), + Value::BulkString(removal_event.into()), + ], + }) + .unwrap(); + + timeout(Duration::from_secs(5), async { + loop { + assert!(!logs_contain("ERROR")); + if logs_contain("Evicting (direct remove) key=DigestInfo(\"3031323334353637383961626364656630303030303030303030303030303030-2\")") { + break; + } + sleep(Duration::from_millis(100)).await; + } + }) + .await + .unwrap(); + + assert!(logs_contain(&format!( + "Removed key removed_key=\"keyprefix:{prefix}3031323334353637383961626364656630303030303030303030303030303030-2\"" + ))); + + Ok(()) +} + +#[nativelink_test] +async fn evict_keys_for_existence_cache_no_prefix() -> Result<(), Error> { + evict_keys_for_existence_cache_core(String::new(), "evicted", logs_contain).await +} + +#[nativelink_test] +async fn evict_keys_for_existence_cache_prefix() -> Result<(), Error> { + evict_keys_for_existence_cache_core(String::from("demo_prefix:"), "evicted", logs_contain).await +} + +/// A key that reaches its TTL has to invalidate the existence cache exactly +/// as a maxmemory eviction does. Redis reports the two differently: `evicted` +/// for maxmemory pressure, `expired` for a TTL. Handling only the former left +/// the cache claiming to hold a key Redis had already dropped, which is +/// newly reachable now that a store can be given a TTL. +#[nativelink_test] +async fn expired_keys_invalidate_the_existence_cache() -> Result<(), Error> { + evict_keys_for_existence_cache_core(String::new(), "expired", logs_contain).await +} + +#[nativelink_test] +async fn expired_keys_invalidate_the_existence_cache_with_prefix() -> Result<(), Error> { + evict_keys_for_existence_cache_core(String::from("demo_prefix:"), "expired", logs_contain).await +} + +/// A store configured with a TTL must expire what it writes. Without this a +/// BEP store keeps every key it ever wrote once its consumer stops, which is +/// how one deployment reached 1.79M keys with `expires=0`. +#[nativelink_test] +async fn update_sets_a_ttl_when_configured() -> Result<(), Error> { + const TTL_SECONDS: u64 = 7 * 24 * 60 * 60; + let data = Bytes::from_static(b"14"); + let digest = DigestInfo::try_new(VALID_HASH1, 2)?; + let packed_hash_hex = format!("{digest}"); + let temp_key = make_temp_key(&packed_hash_hex); + let real_key = packed_hash_hex; + + let store = make_mock_store_with_ttl( + vec![ + MockCmd::new( + redis::cmd("SETRANGE") + .arg(&temp_key) + .arg(0) + .arg(data.to_vec()), + Ok(Value::Int(0)), + ), + // The temp key is guarded as soon as it exists, so an update that + // dies before the rename cannot orphan it. + MockCmd::new( + redis::cmd("EXPIRE") + .arg(&temp_key) + .arg(i64::try_from(TTL_SECONDS).unwrap()), + Ok(Value::Int(1)), + ), + MockCmd::new( + redis::cmd("STRLEN").arg(&temp_key), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), + ), + MockCmd::new( + redis::cmd("RENAME").arg(&temp_key).arg(&real_key), + Ok(Value::Nil), + ), + // Re-set after the rename so the retention window starts at + // completion rather than at the first byte. + MockCmd::new( + redis::cmd("EXPIRE") + .arg(&real_key) + .arg(i64::try_from(TTL_SECONDS).unwrap()), + Ok(Value::Int(1)), + ), + // A read afterwards, purely so the expectations that follow EXPIRE + // get consumed. The mock ignores expectations nobody reaches, so + // without something after it a skipped EXPIRE would pass silently. + MockCmd::with_values( + redis::pipe() + .cmd("STRLEN") + .arg(&real_key) + .cmd("EXISTS") + .arg(&real_key), + Ok(vec![Value::Int(2), Value::Boolean(true)]), + ), + ], + Duration::from_secs(TTL_SECONDS), + ) + .await; + + store.update_oneshot(digest, data).await?; + let size = store.has(digest).await?; + assert_eq!(size, Some(2), "the value must survive the expiry being set"); + Ok(()) +} + +/// A failover between the rename and the expire must not leave the key +/// without a TTL. Every other step in `update` reconnects and retries once on +/// a transient error; this one did not, which review caught after it merged. +#[nativelink_test] +async fn update_retries_the_ttl_after_a_failover() -> Result<(), Error> { + const TTL_SECONDS: u64 = 7 * 24 * 60 * 60; + let data = Bytes::from_static(b"14"); + let digest = DigestInfo::try_new(VALID_HASH1, 2)?; + let packed_hash_hex = format!("{digest}"); + let temp_key = make_temp_key(&packed_hash_hex); + let real_key = packed_hash_hex; + let ttl_arg = i64::try_from(TTL_SECONDS).unwrap(); + + let store = make_mock_store_with_ttl( + vec![ + MockCmd::new( + redis::cmd("SETRANGE") + .arg(&temp_key) + .arg(0) + .arg(data.to_vec()), + Ok(Value::Int(0)), + ), + MockCmd::new( + redis::cmd("EXPIRE").arg(&temp_key).arg(ttl_arg), + Ok(Value::Int(1)), + ), + MockCmd::new( + redis::cmd("STRLEN").arg(&temp_key), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), + ), + MockCmd::new( + redis::cmd("RENAME").arg(&temp_key).arg(&real_key), + Ok(Value::Nil), + ), + // The master goes away right as we set the retention window. + MockCmd::new( + redis::cmd("EXPIRE").arg(&real_key).arg(ttl_arg), + Err::(RedisError::from(std::io::Error::new( + std::io::ErrorKind::ConnectionReset, + "connection reset by peer", + ))), + ), + // After re-resolving the master the TTL is set on the new one. + MockCmd::new( + redis::cmd("EXPIRE").arg(&real_key).arg(ttl_arg), + Ok(Value::Int(1)), + ), + ], + Duration::from_secs(TTL_SECONDS), + ) + .await; + + store.update_oneshot(digest, data).await?; + Ok(()) +} + +/// The default must stay off. The same store type backs the CAS fast tier and +/// the scheduler, and expiring scheduler state would drop in-flight actions. +/// +/// The mock rejects any command it was not given, so an EXPIRE issued here +/// would fail this test. +#[nativelink_test] +async fn update_sets_no_ttl_by_default() -> Result<(), Error> { + let data = Bytes::from_static(b"14"); + let digest = DigestInfo::try_new(VALID_HASH1, 2)?; + let packed_hash_hex = format!("{digest}"); + let temp_key = make_temp_key(&packed_hash_hex); + let real_key = packed_hash_hex; + + let store = make_mock_store(vec![ + MockCmd::new( + redis::cmd("SETRANGE") + .arg(&temp_key) + .arg(0) + .arg(data.to_vec()), + Ok(Value::Int(0)), + ), + MockCmd::new( + redis::cmd("STRLEN").arg(&temp_key), + Ok(Value::Int(data.len().try_into().unwrap_or(i64::MAX))), + ), + MockCmd::new( + redis::cmd("RENAME").arg(&temp_key).arg(&real_key), + Ok(Value::Nil), + ), + ]) + .await; + + store.update_oneshot(digest, data).await?; + Ok(()) +} diff --git a/nativelink-store/tests/ref_store_test.rs b/nativelink-store/tests/ref_store_test.rs index 32cf5c32d..2cf71c6b6 100644 --- a/nativelink-store/tests/ref_store_test.rs +++ b/nativelink-store/tests/ref_store_test.rs @@ -32,7 +32,9 @@ async fn setup_stores() -> (Arc, Store, Store) { let store_manager = Arc::new(StoreManager::new()); let memory_store = Store::new(MemoryStore::new(&MemorySpec::default())); - store_manager.add_store("foo", memory_store.clone()); + store_manager + .add_store("foo", memory_store.clone()) + .expect("adding memory store 'foo' should succeed"); let ref_store = Store::new(RefStore::new( &RefSpec { @@ -40,7 +42,9 @@ async fn setup_stores() -> (Arc, Store, Store) { }, Arc::downgrade(&store_manager), )); - store_manager.add_store("bar", ref_store.clone()); + store_manager + .add_store("bar", ref_store.clone()) + .expect("adding ref store 'bar' should succeed"); store_manager.run_post_init().await.unwrap(); (store_manager, memory_store, ref_store) } @@ -142,7 +146,7 @@ async fn inner_store_test() -> Result<(), Error> { let store_manager = Arc::new(StoreManager::new()); let memory_store = Store::new(MemoryStore::new(&MemorySpec::default())); - store_manager.add_store("mem_store", memory_store.clone()); + store_manager.add_store("mem_store", memory_store.clone())?; let ref_store_inner = Store::new(RefStore::new( &RefSpec { @@ -150,7 +154,7 @@ async fn inner_store_test() -> Result<(), Error> { }, Arc::downgrade(&store_manager), )); - store_manager.add_store("ref_store_inner", ref_store_inner); + store_manager.add_store("ref_store_inner", ref_store_inner)?; let ref_store_outer = Store::new(RefStore::new( &RefSpec { @@ -158,7 +162,7 @@ async fn inner_store_test() -> Result<(), Error> { }, Arc::downgrade(&store_manager), )); - store_manager.add_store("ref_store_outer", ref_store_outer.clone()); + store_manager.add_store("ref_store_outer", ref_store_outer.clone())?; store_manager.run_post_init().await.unwrap(); @@ -177,7 +181,7 @@ async fn no_post_init_failure() -> Result<(), Error> { let store_manager = Arc::new(StoreManager::new()); let memory_store = Store::new(MemoryStore::new(&MemorySpec::default())); - store_manager.add_store("mem_store", memory_store.clone()); + store_manager.add_store("mem_store", memory_store.clone())?; let ref_store = Store::new(RefStore::new( &RefSpec { @@ -185,7 +189,7 @@ async fn no_post_init_failure() -> Result<(), Error> { }, Arc::downgrade(&store_manager), )); - store_manager.add_store("ref_store", ref_store.clone()); + store_manager.add_store("ref_store", ref_store.clone())?; // Should fail because we never called post_init assert_eq!( diff --git a/nativelink-store/tests/store_manager_test.rs b/nativelink-store/tests/store_manager_test.rs new file mode 100644 index 000000000..14aa45a92 --- /dev/null +++ b/nativelink-store/tests/store_manager_test.rs @@ -0,0 +1,32 @@ +// Copyright 2024 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use nativelink_config::stores::MemorySpec; +use nativelink_error::Code; +use nativelink_store::memory_store::MemoryStore; +use nativelink_store::store_manager::StoreManager; +use nativelink_util::store_trait::Store; +use pretty_assertions::assert_eq; + +#[test] +fn add_store_rejects_duplicate_name() { + let store_manager = StoreManager::new(); + store_manager + .add_store("dup", Store::new(MemoryStore::new(&MemorySpec::default()))) + .expect("first add_store should succeed"); + let err = store_manager + .add_store("dup", Store::new(MemoryStore::new(&MemorySpec::default()))) + .expect_err("duplicate store name must be rejected"); + assert_eq!(err.code, Code::AlreadyExists); +} diff --git a/nativelink-store/tests/verify_store_test.rs b/nativelink-store/tests/verify_store_test.rs index dca6b4802..97cc07c81 100644 --- a/nativelink-store/tests/verify_store_test.rs +++ b/nativelink-store/tests/verify_store_test.rs @@ -179,7 +179,11 @@ async fn verify_sha256_hash_true_succeeds_on_update() -> Result<(), Error> { ); let digest = DigestInfo::try_new(HASH, 3).unwrap(); - let result = store.update_oneshot(digest, VALUE.into()).await; + let result = store + .update_oneshot(digest, VALUE.into()) + .instrument(info_span!("update_oneshot")) + .with_context(make_ctx_for_hash_func(DigestHasherFunc::Sha256)?) + .await; assert_eq!(result, Ok(()), "Expected success, got: {:?}", result); assert_eq!( inner_store.has(digest).await, @@ -207,10 +211,15 @@ async fn verify_sha256_hash_true_fails_on_update() -> Result<(), Error> { ); let digest = DigestInfo::try_new(HASH, 3).unwrap(); - let result = store.update_oneshot(digest, VALUE.into()).await; + let result = store + .update_oneshot(digest, VALUE.into()) + .instrument(info_span!("update_oneshot")) + .with_context(make_ctx_for_hash_func(DigestHasherFunc::Sha256)?) + .await; let err = result.unwrap_err().to_string(); - let expected_err = - format!("Hashes do not match, got: {HASH} but digest hash was {ACTUAL_HASH}"); + let expected_err = format!( + "Hash verification using SHA256 failed: client declared SHA256:{HASH}, but the server computed SHA256:{ACTUAL_HASH}" + ); assert!( err.contains(&expected_err), "Error should contain '{expected_err}', got: {err:?}" @@ -283,8 +292,9 @@ async fn verify_blake3_hash_true_fails_on_update() -> Result<(), Error> { // let result = store.update_oneshot(digest, VALUE.into()).await; let err = result.unwrap_err().to_string(); - let expected_err = - format!("Hashes do not match, got: {HASH} but digest hash was {ACTUAL_HASH}"); + let expected_err = format!( + "Hash verification using BLAKE3 failed: client declared BLAKE3:{HASH}, but the server computed BLAKE3:{ACTUAL_HASH}" + ); assert!( err.contains(&expected_err), "Error should contain '{expected_err}', got: {err:?}" @@ -360,7 +370,11 @@ async fn verify_size_and_hash_succeeds_on_small_data() -> Result<(), Error> { ); let digest = DigestInfo::try_new(HASH, 3).unwrap(); - let result = store.update_oneshot(digest, VALUE.into()).await; + let result = store + .update_oneshot(digest, VALUE.into()) + .instrument(info_span!("update_oneshot")) + .with_context(make_ctx_for_hash_func(DigestHasherFunc::Sha256)?) + .await; assert_eq!(result, Ok(()), "Expected success, got: {:?}", result); assert_eq!( inner_store.has(digest).await, diff --git a/nativelink-test/fuzz/Cargo.lock b/nativelink-test/fuzz/Cargo.lock index 9096df349..aec6ab528 100644 --- a/nativelink-test/fuzz/Cargo.lock +++ b/nativelink-test/fuzz/Cargo.lock @@ -17,9 +17,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "arbitrary" @@ -58,7 +58,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -277,7 +277,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.118", ] [[package]] @@ -288,7 +288,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -305,7 +305,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -316,7 +316,7 @@ checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -338,7 +338,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.118", "unicode-xid", ] @@ -361,7 +361,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -463,7 +463,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -684,7 +684,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.4", + "socket2", "tokio", "tower-service", "tracing", @@ -897,7 +897,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -911,7 +911,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -922,7 +922,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -933,7 +933,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1011,7 +1011,7 @@ dependencies = [ "serde_with", "sha1", "sha2", - "socket2 0.6.4", + "socket2", "stringprep", "strsim", "take_mut", @@ -1033,12 +1033,12 @@ dependencies = [ "macro_magic", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] name = "nativelink-config" -version = "1.5.2" +version = "1.6.4" dependencies = [ "byte-unit", "humantime", @@ -1053,8 +1053,9 @@ dependencies = [ [[package]] name = "nativelink-error" -version = "1.5.2" +version = "1.6.4" dependencies = [ + "base64", "mongodb", "nativelink-metric", "nativelink-proto", @@ -1084,7 +1085,7 @@ dependencies = [ [[package]] name = "nativelink-metric" -version = "1.5.2" +version = "1.6.4" dependencies = [ "async-lock", "nativelink-metric-macro-derive", @@ -1095,21 +1096,22 @@ dependencies = [ [[package]] name = "nativelink-metric-macro-derive" -version = "1.5.2" +version = "1.6.4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.1", ] [[package]] name = "nativelink-proto" -version = "1.5.2" +version = "1.6.4" dependencies = [ "derive_more", "prost", "prost-types", "tonic", + "tonic-prost", ] [[package]] @@ -1207,7 +1209,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1237,7 +1239,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1281,9 +1283,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" dependencies = [ "bytes", "prost-derive", @@ -1291,22 +1293,22 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" dependencies = [ "anyhow", "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] name = "prost-types" -version = "0.13.5" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" dependencies = [ "prost", ] @@ -1378,7 +1380,7 @@ dependencies = [ "itoa", "percent-encoding", "ryu", - "socket2 0.6.4", + "socket2", "url", "xxhash-rust", ] @@ -1394,9 +1396,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64", "bytes", @@ -1410,9 +1412,6 @@ dependencies = [ "log", "percent-encoding", "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", "tower", @@ -1572,7 +1571,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1600,18 +1599,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "serde_with" version = "3.21.0" @@ -1631,7 +1618,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1690,16 +1677,6 @@ version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.4" @@ -1750,6 +1727,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5edbec4ed188954a10c12c038215f8ce7606b2d5c973cd8dc43e8795065c5f2f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "sync_wrapper" version = "1.0.2" @@ -1767,7 +1755,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1799,7 +1787,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1877,7 +1865,7 @@ dependencies = [ "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.4", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] @@ -1890,7 +1878,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -1931,9 +1919,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.13.1" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "base64", @@ -1947,8 +1935,8 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "prost", - "socket2 0.5.10", + "socket2", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-stream", @@ -1958,6 +1946,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tower" version = "0.5.3" @@ -2026,7 +2025,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2061,7 +2060,7 @@ checksum = "0e48cea23f68d1f78eb7bc092881b6bb88d3d6b5b7e6234f6f9c911da1ffb221" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2245,7 +2244,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.118", "wasm-bindgen-shared", ] @@ -2420,7 +2419,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "synstructure", ] @@ -2441,7 +2440,7 @@ checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] @@ -2461,7 +2460,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", "synstructure", ] @@ -2501,7 +2500,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.118", ] [[package]] diff --git a/nativelink-util/BUILD.bazel b/nativelink-util/BUILD.bazel index 6b2e4fdc2..a7c5f499a 100644 --- a/nativelink-util/BUILD.bazel +++ b/nativelink-util/BUILD.bazel @@ -7,6 +7,9 @@ load( "rust_test_suite", ) +# Shared with the FastCDC conformance test in nativelink-service. +exports_files(["tests/data/SekienAkashita.jpg"]) + rust_library( name = "nativelink-util", srcs = [ @@ -38,6 +41,7 @@ rust_library( "src/task.rs", "src/telemetry.rs", "src/tls_utils.rs", + "src/wire_compression.rs", ], proc_macro_deps = [ "@crates//:async-trait", @@ -87,6 +91,7 @@ rust_library( "@crates//:uuid", "@crates//:walkdir", "@crates//:wincode", + "@crates//:zstd", ], ) @@ -112,6 +117,7 @@ rust_test_suite( "tests/store_trait_test.rs", "tests/telemetry_test.rs", "tests/tls_utils_test.rs", + "tests/wire_compression_test.rs", ], compile_data = [ "tests/data/SekienAkashita.jpg", @@ -155,10 +161,12 @@ rust_test_suite( "@crates//:tokio-stream", "@crates//:tokio-util", "@crates//:tonic", + "@crates//:tonic-prost", "@crates//:tower", "@crates//:tracing", "@crates//:tracing-test", "@crates//:uuid", + "@crates//:zstd", ], ) diff --git a/nativelink-util/Cargo.toml b/nativelink-util/Cargo.toml index 5ab543189..9b153975f 100644 --- a/nativelink-util/Cargo.toml +++ b/nativelink-util/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-util" -version = "1.5.2" +version = "1.6.4" [dependencies] nativelink-config = { path = "../nativelink-config" } @@ -27,29 +27,29 @@ hyper-util = { version = "0.1.11", default-features = false } libc = { version = "0.2.177", default-features = false } lru = { version = "0.16.0", default-features = false } mock_instant = { version = "0.5.3", default-features = false } -opentelemetry = { version = "0.30.0", default-features = false } -opentelemetry-appender-tracing = { version = "0.30.0", default-features = false } -opentelemetry-http = { version = "0.30.0", default-features = false } -opentelemetry-otlp = { version = "0.30.0", default-features = false, features = [ +opentelemetry = { version = "0.32.0", default-features = false } +opentelemetry-appender-tracing = { version = "0.32.0", default-features = false } +opentelemetry-http = { version = "0.32.0", default-features = false } +opentelemetry-otlp = { version = "0.32.0", default-features = false, features = [ "grpc-tonic", "logs", "metrics", "trace", "zstd-tonic", ] } -opentelemetry-semantic-conventions = { version = "0.30.0", default-features = false, features = [ +opentelemetry-semantic-conventions = { version = "0.32.0", default-features = false, features = [ "default", "semconv_experimental", ] } -opentelemetry_sdk = { version = "0.30.0", default-features = false } +opentelemetry_sdk = { version = "0.32.1", default-features = false } parking_lot = { version = "0.12.3", features = [ "arc_lock", "send_guard", ], default-features = false } pin-project = { version = "1.1.10", default-features = false } pin-project-lite = { version = "0.2.16", default-features = false } -prost = { version = "0.13.5", default-features = false } -prost-types = { version = "0.13.5", default-features = false, features = [ +prost = { version = "0.14.4", default-features = false } +prost-types = { version = "0.14.4", default-features = false, features = [ "std", ] } rand = { version = "0.9.0", default-features = false, features = [ @@ -69,7 +69,7 @@ tokio-stream = { version = "0.1.17", features = [ "fs", ], default-features = false } tokio-util = { version = "0.7.14", default-features = false } -tonic = { version = "0.13.0", features = [ +tonic = { version = "0.14.0", features = [ "router", "tls-native-roots", "tls-ring", @@ -77,7 +77,7 @@ tonic = { version = "0.13.0", features = [ ], default-features = false } tower = { version = "0.5.2", default-features = false } tracing = { version = "0.1.41", default-features = false } -tracing-opentelemetry = { version = "0.31.0", default-features = false, features = [ +tracing-opentelemetry = { version = "0.33.0", default-features = false, features = [ "metrics", ] } tracing-subscriber = { version = "0.3.19", features = [ @@ -86,8 +86,8 @@ tracing-subscriber = { version = "0.3.19", features = [ "json", ], default-features = false } tracing-test = { version = "0.2.5", default-features = false, features = [] } - -ginepro = { version = "0.9.3", default-features = false } +# FIXME: Replace with version once https://github.com/TrueLayer/ginepro/pull/77 is fixed +ginepro = { git = "https://github.com/mstyura/ginepro", rev = "d08cdeff6300edfb46204b3b9fbde3f3355db35f", default-features = false } url = { version = "2.5.7", default-features = false } uuid = { version = "1.16.0", default-features = false, features = [ "serde", @@ -96,11 +96,12 @@ uuid = { version = "1.16.0", default-features = false, features = [ ] } walkdir = { version = "2.5.0", default-features = false } wincode = { version = "0.5.4", default-features = false, features = ["derive"] } +zstd = { version = "0.13.3", default-features = false } [dev-dependencies] -anyhow = { version = "1.0.100", default-features = false } +anyhow = { version = "1.0.103", default-features = false } nativelink-macro = { path = "../nativelink-macro" } -opentelemetry-proto = { version = "0.30.0", default-features = false, features = [ +opentelemetry-proto = { version = "0.32.0", default-features = false, features = [ "gen-tonic", "metrics", ] } @@ -120,6 +121,7 @@ serde_json = { version = "1.0.140", default-features = false } tokio = { version = "1.52.2", features = [ "test-util", ], default-features = false } +tonic-prost = { version = "0.14.6", default-features = false } tracing-test = { version = "0.2.5", default-features = false, features = [ "no-env-filter", ] } diff --git a/nativelink-util/src/buf_channel.rs b/nativelink-util/src/buf_channel.rs index 9632a112e..b685ca623 100644 --- a/nativelink-util/src/buf_channel.rs +++ b/nativelink-util/src/buf_channel.rs @@ -72,6 +72,30 @@ impl DropCloserWriteHalf { self.send_get_bytes_on_error(buf).map_err(|err| err.0) } + /// Sends data over the channel to the receiver from a blocking thread. + pub fn blocking_send(&mut self, buf: Bytes) -> Result<(), Error> { + let tx = self + .tx + .as_ref() + .ok_or_else(|| make_err!(Code::Internal, "Tried to send while stream is closed"))?; + let buf_len = u64::try_from(buf.len()).err_tip(|| "Could not convert usize to u64")?; + if buf_len == 0 { + return Err(make_input_err!( + "Cannot send EOF in blocking_send(). Instead use send_eof()" + )); + } + if let Err(err) = tx.blocking_send(buf) { + self.tx = None; + return Err(make_err!( + Code::Internal, + "Failed to write to data, receiver disconnected: {} bytes", + err.0.len() + )); + } + self.bytes_written += buf_len; + Ok(()) + } + /// Sends data over the channel to the receiver. #[inline] async fn send_get_bytes_on_error(&mut self, buf: Bytes) -> Result<(), (Error, Bytes)> { @@ -255,6 +279,17 @@ impl DropCloserReadHalf { } } + /// Receive a chunk of data from a blocking thread. + pub fn blocking_recv(&mut self) -> Result { + if let Some(result) = self.try_recv() { + result + } else { + // `None` here indicates EOF, which we represent as Zero data + let data = self.rx.blocking_recv().unwrap_or(ZERO_DATA); + self.recv_inner(data) + } + } + fn maybe_populate_recent_data(&mut self, chunk: &Bytes) { if self.max_recent_data_size == 0 { return; // Fast path. diff --git a/nativelink-util/src/common.rs b/nativelink-util/src/common.rs index 554c94d78..d5bd6a9d1 100644 --- a/nativelink-util/src/common.rs +++ b/nativelink-util/src/common.rs @@ -155,13 +155,13 @@ impl<'a> DigestStackStringifier<'a> { })?; cursor .write_all(&hex) - .err_tip(|| format!("Could not write hex to buffer - {hex:?} - {hex:?}",))?; + .err_tip(|| format!("Could not write hex to buffer - {hex:?} - {hex:?}"))?; // Note: We already have a hyphen at this point because we // initialized the buffer with hyphens. cursor.advance(1); cursor .write_fmt(format_args!("{}", self.digest.size_bytes())) - .err_tip(|| format!("Could not write size_bytes to buffer - {hex:?}",))?; + .err_tip(|| format!("Could not write size_bytes to buffer - {hex:?}"))?; cursor.position().try_into().map_err(|e| { Error::from_std_err(Code::InvalidArgument, &e) .append("Cursor position exceeds usize bounds") diff --git a/nativelink-util/src/connection_manager.rs b/nativelink-util/src/connection_manager.rs index 06f66467b..9dfad7bdc 100644 --- a/nativelink-util/src/connection_manager.rs +++ b/nativelink-util/src/connection_manager.rs @@ -27,6 +27,7 @@ use tonic::transport::{Channel, Endpoint, channel}; use tracing::{debug, error, info, warn}; use crate::background_spawn; +use crate::metrics::record_connection_acquired; use crate::retry::{self, Retrier, RetryResult}; /// A helper utility that enables management of a suite of connections to an @@ -102,6 +103,10 @@ struct ConnectionManagerWorker { /// round-trip that could be lost on tonic transport errors or task /// aborts. available_connections: Arc, + + /// Whether `available_connections` reflects a configured limit. When the + /// pool is unlimited its permit count is a sentinel, not a measurement. + bounded_connections: bool, /// Channels that are currently being connected. connecting_channels: FuturesUnordered + Send>>>, /// Connected channels that are available for use. @@ -140,6 +145,10 @@ impl ConnectionManager { .map(|endpoint| (0, endpoint)) .collect(); + // Zero means unlimited, which becomes a semaphore holding + // Semaphore::MAX_PERMITS. That is a sentinel, not a free-slot count, + // so remember which case this is and report no figure when unbounded. + let bounded_connections = max_concurrent_requests != 0; if max_concurrent_requests == 0 { max_concurrent_requests = Semaphore::MAX_PERMITS; } else { @@ -151,6 +160,7 @@ impl ConnectionManager { let worker = ConnectionManagerWorker { endpoints, available_connections: Arc::new(Semaphore::new(max_concurrent_requests)), + bounded_connections, connection_tx, connecting_channels: FuturesUnordered::new(), available_channels: VecDeque::new(), @@ -314,6 +324,13 @@ impl ConnectionManagerWorker { })); } + /// Free slots, or `None` when the pool is unlimited and the permit count + /// is a sentinel rather than a measurement. + fn free_connection_slots(&self) -> Option { + self.bounded_connections + .then(|| self.available_connections.available_permits()) + } + // This must never be made async otherwise the select may cancel it. fn handle_worker(&mut self, reason: String, tx: oneshot::Sender) { let maybe_permit = self.available_connections.clone().try_acquire_owned().ok(); @@ -321,6 +338,7 @@ impl ConnectionManagerWorker { && let Some(channel) = self.available_channels.pop_front() { debug!(reason, "ConnectionManager: request running"); + record_connection_acquired("grpc", self.free_connection_slots(), false); self.provide_channel(channel, tx, permit); } else { debug!( @@ -330,6 +348,7 @@ impl ConnectionManagerWorker { reason, "ConnectionManager: no connection available, request queued", ); + record_connection_acquired("grpc", self.free_connection_slots(), true); self.waiting_connections.push_back((reason, tx)); } } diff --git a/nativelink-util/src/digest_hasher.rs b/nativelink-util/src/digest_hasher.rs index 51c911c63..e0a37b0af 100644 --- a/nativelink-util/src/digest_hasher.rs +++ b/nativelink-util/src/digest_hasher.rs @@ -53,6 +53,14 @@ pub fn default_digest_hasher_func() -> DigestHasherFunc { *DEFAULT_DIGEST_HASHER_FUNC.get_or_init(|| DigestHasherFunc::Sha256) } +/// Get the hasher requested by the client from the active context (set via +/// [`make_ctx_for_hash_func`]), falling back to the default hasher. +pub fn digest_hasher_func_from_context() -> DigestHasherFunc { + Context::current() + .get::() + .map_or_else(default_digest_hasher_func, |v| *v) +} + /// Sets the default hasher to use if no hasher was requested by the client. pub fn set_default_digest_hasher_func(hasher: DigestHasherFunc) -> Result<(), Error> { DEFAULT_DIGEST_HASHER_FUNC diff --git a/nativelink-util/src/evicting_map.rs b/nativelink-util/src/evicting_map.rs index 614a51350..dc12919c4 100644 --- a/nativelink-util/src/evicting_map.rs +++ b/nativelink-util/src/evicting_map.rs @@ -20,7 +20,7 @@ use core::hash::Hash; use core::marker::PhantomData; use core::ops::RangeBounds; use core::pin::Pin; -use std::collections::BTreeSet; +use std::collections::{BTreeSet, HashMap}; use std::sync::Arc; use futures::StreamExt; @@ -105,8 +105,20 @@ struct State< > { lru: LruCache>, btree: Option>, + /// A mirror of `lru` that contains only currently unleased keys. + /// Keeping this index in LRU order lets eviction visit candidates without + /// scanning entries that an active operation has pinned. + evictable_lru: LruCache, + /// Reference counts for keys that must not be evicted while an active + /// operation is using them. A key can be leased before it is inserted, + /// which closes the admission-to-insert race for cache populations. + leases: HashMap, #[metric(help = "Total size of all items in the store")] sum_store_size: u64, + #[metric(help = "Number of items currently leased and not evictable")] + leased_items: u64, + #[metric(help = "Number of bytes currently leased and not evictable")] + leased_bytes: u64, #[metric(help = "Number of bytes evicted from the store")] evicted_bytes: Counter, @@ -132,6 +144,88 @@ impl< C: RemoveItemCallback, > State { + fn is_leased(&self, key: &Q) -> bool { + self.leases.contains_key(key) + } + + /// Keep candidate recency aligned with a normal read from `lru`. + /// Returns whether the key is leased so callers do not repeat the lookup. + fn touch_evictable(&mut self, key: &Q) -> bool { + if self.is_leased(key) { + return true; + } + self.evictable_lru.get(key); + false + } + + /// Add a newly written key to the candidate index unless it is reserved + /// by a lease that was acquired before insertion. + fn insert_evictable(&mut self, key: K) { + if !self.is_leased(key.borrow()) { + self.evictable_lru.put(key, ()); + } + } + + fn lease(&mut self, key: K) { + if let Some(lease_count) = self.leases.get_mut(key.borrow()) { + *lease_count = lease_count.checked_add(1).expect("lease count overflow"); + return; + } + + self.evictable_lru.pop(key.borrow()); + if let Some(entry) = self.lru.peek(key.borrow()) { + self.leased_bytes += entry.data.len(); + } + self.leased_items += 1; + self.leases.insert(key, 1); + } + + /// Release one reference and return the owned key when the lease ends. + fn release_lease(&mut self, key: &Q) -> Option { + let lease_count = self.leases.get_mut(key)?; + if *lease_count > 1 { + *lease_count -= 1; + return None; + } + + let leased_key = self + .leases + .remove_entry(key) + .expect("Lease must exist when its final reference is released") + .0; + self.leased_items -= 1; + if let Some(entry) = self.lru.peek(leased_key.borrow()) { + self.leased_bytes -= entry.data.len(); + } + Some(leased_key) + } + + /// Re-enter a resident key as the newest eviction candidate. Its age is + /// intentionally preserved, so a long lease does not extend the TTL. + fn reinsert_evictable(&mut self, key: K) { + if self.lru.peek(key.borrow()).is_some() { + self.evictable_lru.put(key, ()); + } + } + + fn peek_evictable(&self) -> Option<&EvictionItem> { + let (key, ()) = self.evictable_lru.peek_lru()?; + Some( + self.lru + .peek(key.borrow()) + .expect("Evictable LRU key must be resident in the main LRU"), + ) + } + + fn pop_evictable(&mut self) -> Option<(K, EvictionItem)> { + let (candidate_key, ()) = self.evictable_lru.pop_lru()?; + let (key, entry) = self + .lru + .pop_entry(candidate_key.borrow()) + .expect("Evictable LRU key must be resident in the main LRU"); + Some((key, entry)) + } + /// Removes an item from the cache and returns the data for deferred cleanup. /// The caller is responsible for calling `unref()` on the returned data outside of the lock. #[must_use] @@ -147,6 +241,11 @@ impl< if let Some(btree) = &mut self.btree { btree.remove(key); } + // Keep every auxiliary resident index in sync with the main LRU. + self.evictable_lru.pop(key); + if self.is_leased(key) { + self.leased_bytes -= eviction_item.data.len(); + } self.sum_store_size -= eviction_item.data.len(); if replaced { self.replaced_items.inc(); @@ -174,13 +273,24 @@ impl< K: Clone, T: Clone, { - // If we are maintaining a btree index, we need to update it. + let is_leased = self.is_leased(key.borrow()); + let new_item_size = eviction_item.data.len(); + let replaced_item = self + .lru + .put(key.clone(), eviction_item) + .map(|old_item| self.remove(key.borrow(), &old_item, true)); + + if is_leased { + self.leased_bytes += new_item_size; + } + // `remove()` drops the old key from both indexes. Reinsert it after + // replacement so an unleased write is MRU in both LRU indexes. + self.insert_evictable(key.clone()); if let Some(btree) = &mut self.btree { btree.insert(key.clone()); } - self.lru - .put(key.clone(), eviction_item) - .map(|old_item| self.remove(key.borrow(), &old_item, true)) + + replaced_item } fn add_remove_callback(&mut self, callback: C) { @@ -276,7 +386,11 @@ where state: Mutex::new(State { lru: LruCache::unbounded(), btree: None, + evictable_lru: LruCache::unbounded(), + leases: HashMap::new(), sum_store_size: 0, + leased_items: 0, + leased_bytes: 0, evicted_bytes: Counter::default(), evicted_items: CounterWithTime::default(), replaced_bytes: Counter::default(), @@ -288,7 +402,7 @@ where anchor_time, max_bytes: config.max_bytes as u64, evict_bytes: config.evict_bytes as u64, - max_seconds: config.max_seconds as i32, + max_seconds: config.max_seconds.try_into().unwrap_or(i32::MAX), max_count: config.max_count, } } @@ -347,8 +461,7 @@ where ) -> bool { let is_over_size = max_bytes != 0 && sum_store_size >= max_bytes; - let elapsed_seconds = - i32::try_from(self.anchor_time.elapsed().as_secs()).unwrap_or(i32::MAX); + let elapsed_seconds = self.elapsed_seconds(); let evict_older_than_seconds = elapsed_seconds.saturating_sub(self.max_seconds); let old_item_exists = self.max_seconds != 0 && peek_entry.seconds_since_anchor < evict_older_than_seconds; @@ -359,6 +472,10 @@ where is_over_size || old_item_exists || is_over_count } + fn elapsed_seconds(&self) -> i32 { + i32::try_from(self.anchor_time.elapsed().as_secs()).unwrap_or(i32::MAX) + } + // Gets a debugging snapshot of the state of the map. It's inevitably out of date by the time it gets sent to the user // but does provide a momentary glimpse into possible issues e.g. if current_bytes is close to max_bytes pub fn get_snapshot(&self) -> EvictionSnapshot { @@ -374,15 +491,28 @@ where #[must_use] fn evict_items(&self, state: &mut State) -> (Vec, Vec) { - let Some((_, mut peek_entry)) = state.lru.peek_lru() else { + let Some(first_entry) = state.peek_evictable() else { + if !state.lru.is_empty() { + debug!( + resident_items = state.lru.len(), + evictable_items = state.evictable_lru.len(), + lease_keys = state.leases.len(), + leased_items = state.leased_items, + leased_bytes = state.leased_bytes, + resident_bytes = state.sum_store_size, + "Eviction requested, but every resident entry is leased", + ); + } return (Vec::new(), Vec::new()); }; + // Preserve the configured low-watermark behavior: once pressure is + // detected, keep evicting until `evict_bytes` is reclaimed. let max_bytes = if self.max_bytes != 0 && self.evict_bytes != 0 && self.should_evict( state.lru.len(), - peek_entry, + first_entry, state.sum_store_size, self.max_bytes, ) { @@ -394,21 +524,20 @@ where let mut items_to_unref = Vec::new(); let mut removal_futures = Vec::new(); - while self.should_evict(state.lru.len(), peek_entry, state.sum_store_size, max_bytes) { + // Pop the candidate index directly instead of collecting and cloning + // all victim keys. Both indexes are protected by the same lock. + while let Some(entry) = state.peek_evictable() { + if !self.should_evict(state.lru.len(), entry, state.sum_store_size, max_bytes) { + break; + } + let (key, eviction_item) = state - .lru - .pop_lru() - .expect("Tried to peek() then pop() but failed"); + .pop_evictable() + .expect("Evictable LRU key disappeared while state was locked"); debug!(?key, "Evicting"); let (data, futures) = state.remove(key.borrow(), &eviction_item, false); items_to_unref.push(data); - removal_futures.extend(futures.into_iter()); - - peek_entry = if let Some((_, entry)) = state.lru.peek_lru() { - entry - } else { - break; - }; + removal_futures.extend(futures); } (items_to_unref, removal_futures) @@ -447,6 +576,11 @@ where let mut data_to_unref = Vec::new(); let mut removal_futures = Vec::new(); for (key, result) in keys.into_iter().zip(results.iter_mut()) { + let is_leased = if peek { + state.is_leased(key.borrow()) + } else { + state.touch_evictable(key.borrow()) + }; let maybe_entry = if peek { state.lru.peek_mut(key.borrow()) } else { @@ -457,7 +591,7 @@ where // Note: We need to check eviction because the item might be expired // based on the current time. In such case, we remove the item while // we are here. - if self.should_evict(lru_len, entry, 0, u64::MAX) { + if !is_leased && self.should_evict(lru_len, entry, 0, u64::MAX) { *result = None; if let Some((key, eviction_item)) = state.lru.pop_entry(key.borrow()) { info!(?key, "Item expired, evicting"); @@ -465,13 +599,11 @@ where state.remove(key.borrow(), &eviction_item, false); // Store data for later unref - we can't drop state here as we're still iterating data_to_unref.push(data); - removal_futures.extend(futures.into_iter()); + removal_futures.extend(futures); } } else { if !peek { - entry.seconds_since_anchor = - i32::try_from(self.anchor_time.elapsed().as_secs()) - .unwrap_or(i32::MAX); + entry.seconds_since_anchor = self.elapsed_seconds(); } *result = Some(entry.data.len()); } @@ -524,11 +656,12 @@ where let (data, expired_data, removal_futures) = { let mut state = self.state.lock(); let lru_len = state.lru.len(); + let is_leased = state.touch_evictable(key.borrow()); let entry = state.lru.get_mut(key.borrow())?; // Pass `sum_store_size=0` and `max_bytes=u64::MAX` so we only // consult TTL / count predicates — never the global byte budget. // Mirrors the per-key reap path in `sizes_for_keys`. - if self.should_evict(lru_len, entry, 0, u64::MAX) { + if !is_leased && self.should_evict(lru_len, entry, 0, u64::MAX) { let (popped_key, eviction_item) = state .lru .pop_entry(key.borrow()) @@ -537,8 +670,7 @@ where let (data, futures) = state.remove(popped_key.borrow(), &eviction_item, false); (None, Some(data), futures) } else { - entry.seconds_since_anchor = - i32::try_from(self.anchor_time.elapsed().as_secs()).unwrap_or(i32::MAX); + entry.seconds_since_anchor = self.elapsed_seconds(); (Some(entry.data.clone()), None, Vec::new()) } }; @@ -558,12 +690,8 @@ where where K: 'static, { - self.insert_with_time( - key, - data, - i32::try_from(self.anchor_time.elapsed().as_secs()).unwrap_or(i32::MAX), - ) - .await + self.insert_with_time(key, data, self.elapsed_seconds()) + .await } /// Returns the replaced item if any. @@ -605,11 +733,7 @@ where let (items_to_unref, removal_futures) = { let mut state = self.state.lock(); - self.inner_insert_many( - &mut state, - inserts, - i32::try_from(self.anchor_time.elapsed().as_secs()).unwrap_or(i32::MAX), - ) + self.inner_insert_many(&mut state, inserts, self.elapsed_seconds()) }; let mut futures: FuturesUnordered<_> = removal_futures.into_iter().collect(); @@ -627,6 +751,59 @@ where .await } + /// Lease a key so automatic size, count, and expiry eviction cannot remove it. + /// + /// Leasing before the value is inserted is intentional: an action can + /// reserve a digest before populating the fast tier, so insertion and + /// eviction cannot race with the start of input materialization. Explicit + /// `remove` and `remove_if` calls still remove leased entries; those paths + /// are used for deliberate deletion and filesystem self-healing. + pub fn lease_key(&self, key: K) { + self.state.lock().lease(key); + } + + /// Release one lease and trim any entries that were retained while the + /// lease was active. + pub async fn release_key(&self, key: &Q) { + self.release_keys([key]).await; + } + + /// Release a batch of leases and trim retained entries once. + /// + /// Action input leases commonly contain thousands of digests. Batching + /// avoids rescanning the LRU and running deferred cleanup once per digest + /// during action teardown. + pub async fn release_keys(&self, keys: It) + where + It: IntoIterator + Send, + ::IntoIter: Send, + R: Borrow + Send, + { + let (items_to_unref, removal_futures) = { + let mut state = self.state.lock(); + let mut released_any = false; + for key in keys { + if let Some(leased_key) = state.release_lease(key.borrow()) { + // A released key re-enters as MRU, giving an actively used + // input a fair chance to remain cached after its action. + state.reinsert_evictable(leased_key); + released_any = true; + } + } + if released_any { + self.evict_items(&mut state) + } else { + (Vec::new(), Vec::new()) + } + }; + + let mut futures: FuturesUnordered<_> = removal_futures.into_iter().collect(); + while futures.next().await.is_some() {} + + let mut futures: FuturesUnordered<_> = items_to_unref.iter().map(LenEntry::unref).collect(); + while futures.next().await.is_some() {} + } + fn inner_insert_many( &self, state: &mut State, @@ -649,7 +826,7 @@ where }; if let Some((old_item, futures)) = state.put(&key, eviction_item) { - removal_futures.extend(futures.into_iter()); + removal_futures.extend(futures); debug!(?key, "Evicting old item"); replaced_items.push(old_item); } @@ -678,7 +855,7 @@ where // Then try to remove the requested item let removed = if let Some(entry) = state.lru.pop(key.borrow()) { let (removed_item, more_removal_futures) = state.remove(key, &entry, false); - removal_futures.extend(more_removal_futures.into_iter()); + removal_futures.extend(more_removal_futures); Some(removed_item) } else { None @@ -713,26 +890,27 @@ where { let (evicted_items, removal_futures, removed_item) = { let mut state = self.state.lock(); - if let Some(entry) = state.lru.get(key.borrow()) { - if !cond(&entry.data) { - return false; - } - // First perform eviction - let (evicted_items, mut removal_futures) = self.evict_items(&mut state); - - // Then try to remove the requested item - let removed_item = if let Some(entry) = state.lru.pop(key.borrow()) { - let (item, more_removal_futures) = state.remove(key, &entry, false); - removal_futures.extend(more_removal_futures.into_iter()); - Some(item) - } else { - None - }; + state.touch_evictable(key.borrow()); + let Some(entry) = state.lru.get(key.borrow()) else { + return false; + }; + if !cond(&entry.data) { + return false; + } + + // First perform eviction + let (evicted_items, mut removal_futures) = self.evict_items(&mut state); - (evicted_items, removal_futures, removed_item) + // Then try to remove the requested item + let removed_item = if let Some(entry) = state.lru.pop(key.borrow()) { + let (item, more_removal_futures) = state.remove(key, &entry, false); + removal_futures.extend(more_removal_futures); + Some(item) } else { - (vec![], vec![].into_iter().collect(), None) - } + None + }; + + (evicted_items, removal_futures, removed_item) }; // Perform the async callbacks outside of the lock diff --git a/nativelink-util/src/fs.rs b/nativelink-util/src/fs.rs index bf5d95e40..47c5ccf3f 100644 --- a/nativelink-util/src/fs.rs +++ b/nativelink-util/src/fs.rs @@ -440,7 +440,7 @@ fn internal_remove_dir_all(path: impl AsRef) -> Result<(), Error> { for entry in WalkDir::new(&path) { let Ok(entry) = &entry else { - debug!("Can't get into {entry:?}, assuming already deleted"); + debug!(?entry, "Can't get entry, assuming already deleted"); continue; }; let metadata = entry.metadata()?; diff --git a/nativelink-util/src/fs_util.rs b/nativelink-util/src/fs_util.rs index 40fc1e121..b18cc66f6 100644 --- a/nativelink-util/src/fs_util.rs +++ b/nativelink-util/src/fs_util.rs @@ -65,8 +65,9 @@ pub enum CloneMethod { /// defensive guarantee for callers that did not pre-mark the source. /// - Linux: Per-file `fs::hard_link` (directory hardlinks are not supported on /// ext4/btrfs without root). Directories at the destination are created -/// fresh by this walk, so they are writable regardless of the source's -/// directory modes; files are hardlinked and keep the source inode's mode. +/// fresh by this walk and chmod'd to a stable, umask-independent 0o755, so +/// they are writable regardless of the source's directory modes and of the +/// process umask; files are hardlinked and keep the source inode's mode. /// Always returns `CloneMethod::Hardlink`. /// - Windows: Per-file `fs::hard_link` (requires NTFS). Always returns /// `CloneMethod::Hardlink`. @@ -143,12 +144,34 @@ pub async fn hardlink_directory_tree(src_dir: &Path, dst_dir: &Path) -> Result Result<(), Error> { + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + fs::set_permissions(dir, std::fs::Permissions::from_mode(0o755)) + .await + .err_tip(|| format!("Failed to set directory mode: {}", dir.display()))?; + } + #[cfg(not(unix))] + let _ = dir; + Ok(()) +} + /// Recursively clones a directory tree using APFS `clonefile(2)`. On success /// the destination shares data blocks with the source via copy-on-write; the /// operation is O(1) in tree size regardless of file count. @@ -276,6 +299,7 @@ fn hardlink_directory_tree_recursive<'a>( fs::create_dir(&dst_path) .await .err_tip(|| format!("Failed to create directory: {}", dst_path.display()))?; + chmod_dir_0o755(&dst_path).await?; hardlink_directory_tree_recursive(&entry_path, &dst_path).await?; } else if metadata.is_file() { diff --git a/nativelink-util/src/health_utils.rs b/nativelink-util/src/health_utils.rs index baa9f564c..2330caf25 100644 --- a/nativelink-util/src/health_utils.rs +++ b/nativelink-util/src/health_utils.rs @@ -26,6 +26,8 @@ use serde::Serialize; use tokio::time::timeout; use tracing::warn; +use crate::metrics::record_health_check; + /// Struct name health indicator component. type StructName = str; /// Readable message status of the health indicator. @@ -56,6 +58,19 @@ pub enum HealthStatus { } impl HealthStatus { + /// Stable label for metrics. Part of the wire contract, so dashboards + /// break if these strings change. + #[must_use] + pub const fn metric_label(&self) -> &'static str { + match self { + Self::Ok { .. } => "ok", + Self::Initializing { .. } => "initializing", + Self::Warning { .. } => "warning", + Self::Failed { .. } => "failed", + Self::Timeout { .. } => "timeout", + } + } + pub fn new_ok( component: &(impl HealthStatusIndicator + ?Sized), message: Cow<'static, str>, @@ -225,13 +240,15 @@ impl HealthStatusReporter for HealthRegistry { indicator.check_health(namespace.clone()), ) .await; + let status = status_res.unwrap_or_else(|_| { + let struct_name = indicator.struct_name(); + warn!(struct_name, "Timeout during health check"); + HealthStatus::Timeout { struct_name } + }); + record_health_check(namespace, status.metric_label()); HealthStatusDescription { namespace: namespace.clone(), - status: status_res.unwrap_or_else(|_| { - let struct_name = indicator.struct_name(); - warn!(struct_name, "Timeout during health check"); - HealthStatus::Timeout { struct_name } - }), + status, } }, )) diff --git a/nativelink-util/src/lib.rs b/nativelink-util/src/lib.rs index 932c21bb0..d082f3c3a 100644 --- a/nativelink-util/src/lib.rs +++ b/nativelink-util/src/lib.rs @@ -39,6 +39,7 @@ pub mod store_trait; pub mod task; pub mod telemetry; pub mod tls_utils; +pub mod wire_compression; // Re-export tracing mostly for use in macros. pub use tracing as __tracing; diff --git a/nativelink-util/src/metrics.rs b/nativelink-util/src/metrics.rs index c04a75cc7..671f2436f 100644 --- a/nativelink-util/src/metrics.rs +++ b/nativelink-util/src/metrics.rs @@ -15,10 +15,11 @@ // limitations under the License. use std::sync::LazyLock; +use std::time::SystemTime; use opentelemetry::{InstrumentationScope, KeyValue, Value, global, metrics}; -use crate::action_messages::ActionStage; +use crate::action_messages::{ActionResult, ActionStage}; // Metric attribute keys for cache operations. pub const CACHE_TYPE: &str = "cache.type"; @@ -34,6 +35,50 @@ pub const EXECUTION_WORKER_ID: &str = "execution.worker_id"; pub const EXECUTION_EXIT_CODE: &str = "execution.exit_code"; pub const EXECUTION_ACTION_DIGEST: &str = "execution.action_digest"; +// Metric attribute keys for gRPC serving, following OTel rpc semconv. +pub const RPC_SERVICE: &str = "rpc.service"; +pub const RPC_METHOD: &str = "rpc.method"; +pub const RPC_STATUS_CODE: &str = "rpc.grpc.status_code"; + +// Metric attribute keys for the scheduler. +pub const SCHEDULER_MATCH_RESULT: &str = "scheduler.match.result"; + +// Metric attribute keys for tiered stores. +pub const STORE_TIER: &str = "store.tier"; +pub const STORE_RESULT: &str = "store.result"; +pub const STORE_DIRECTION: &str = "store.direction"; + +// Metric attribute keys for connection pools. +pub const CONNECTION_POOL: &str = "connection.pool"; +pub const CONNECTION_RESULT: &str = "connection.result"; + +// Metric attribute keys for health checks. +pub const HEALTH_NAMESPACE: &str = "health.namespace"; +pub const HEALTH_STATUS: &str = "health.status"; + +// Metric attribute keys for the worker fleet. +pub const WORKER_STATE: &str = "worker.state"; +pub const WORKER_DISCONNECT_REASON: &str = "worker.disconnect.reason"; + +/// Why a worker left the pool. +#[derive(Debug, Clone, Copy)] +pub enum WorkerDisconnectReason { + /// The worker's connection ended. + Disconnected, + /// The scheduler evicted it, usually after a timeout or an error. + Evicted, +} + +impl WorkerDisconnectReason { + #[must_use] + pub const fn as_str(self) -> &'static str { + match self { + Self::Disconnected => "disconnected", + Self::Evicted => "evicted", + } + } +} + /// Cache operation types for metrics classification. #[derive(Debug, Clone, Copy)] pub enum CacheOperationName { @@ -550,52 +595,44 @@ pub static EXECUTION_METRICS: LazyLock = LazyLock::new(|| { .with_unit("{transition}") .build(), - execution_output_size: meter - .u64_histogram("execution.output.size") - .with_description("Size of execution outputs in bytes") - .with_unit("By") + execution_cpu_time: meter + .f64_histogram("execution.cpu.time") + .with_description("CPU time consumed by an action in seconds") + .with_unit("s") .with_boundaries(vec![ - 1_024.0, // 1KB - 10_240.0, // 10KB - 102_400.0, // 100KB - 1_048_576.0, // 1MB - 10_485_760.0, // 10MB - 104_857_600.0, // 100MB - 1_073_741_824.0, // 1GB - 10_737_418_240.0, // 10GB + 0.1, 0.5, 1.0, 5.0, 10.0, 30.0, 60.0, 300.0, 600.0, 1800.0, 3600.0, 7200.0, ]) .build(), - execution_cpu_time: meter - .f64_histogram("execution.cpu.time") - .with_description("CPU time consumed by action execution in seconds") - .with_unit("s") + execution_peak_memory: meter + .u64_histogram("execution.peak.memory") + .with_description("Peak resident memory observed while running an action in bytes") + .with_unit("By") .with_boundaries(vec![ - 0.01, // 10ms - 0.1, // 100ms - 1.0, // 1s - 10.0, // 10s - 60.0, // 1 minute - 300.0, // 5 minutes - 600.0, // 10 minutes - 1800.0, // 30 minutes - 3600.0, // 1 hour + 1_048_576.0, // 1MiB + 16_777_216.0, // 16MiB + 67_108_864.0, // 64MiB + 268_435_456.0, // 256MiB + 1_073_741_824.0, // 1GiB + 4_294_967_296.0, // 4GiB + 17_179_869_184.0, // 16GiB + 68_719_476_736.0, // 64GiB ]) .build(), - execution_memory_usage: meter - .u64_histogram("execution.memory.usage") - .with_description("Peak memory usage during execution in bytes") + execution_output_size: meter + .u64_histogram("execution.output.size") + .with_description("Size of execution outputs in bytes") .with_unit("By") .with_boundaries(vec![ + 1_024.0, // 1KB + 10_240.0, // 10KB + 102_400.0, // 100KB 1_048_576.0, // 1MB 10_485_760.0, // 10MB 104_857_600.0, // 100MB - 524_288_000.0, // 500MB 1_073_741_824.0, // 1GB - 5_368_709_120.0, // 5GB 10_737_418_240.0, // 10GB - 53_687_091_200.0, // 50GB ]) .build(), @@ -624,12 +661,61 @@ pub struct ExecutionMetrics { pub execution_stage_transitions: metrics::Counter, /// Histogram of output sizes in bytes pub execution_output_size: metrics::Histogram, - /// Histogram of CPU time in seconds - pub execution_cpu_time: metrics::Histogram, - /// Histogram of peak memory usage in bytes - pub execution_memory_usage: metrics::Histogram, /// Counter for execution retries pub execution_retry_count: metrics::Counter, + /// Peak memory an action used, as sampled by the worker. + pub execution_peak_memory: metrics::Histogram, + /// CPU time an action used, as sampled by the worker. + pub execution_cpu_time: metrics::Histogram, +} + +/// Records the CPU time a worker observed for an action. +/// +/// Wall time is already covered by `execution.stage.duration`. This is the +/// other half: an action pinning eight cores for a minute and one sleeping +/// for a minute look identical by wall time and nothing alike here. +pub fn record_execution_cpu_time(cpu_time_ms: u64, instance_name: &str) { + #[expect(clippy::cast_precision_loss)] // Milliseconds; f64 is exact well past any real action. + let seconds = cpu_time_ms as f64 / 1000.0; + EXECUTION_METRICS.execution_cpu_time.record( + seconds, + &[KeyValue::new(EXECUTION_INSTANCE, instance_name.to_string())], + ); +} + +/// Records the peak memory a worker observed while running an action. +/// +/// The worker samples this, so it is only present when sampling ran. #2614 +/// listed `execution_memory_usage` as unimplementable because +/// `ExecutionMetadata` carries no memory figure; `ActionResourceUsage` does, +/// and this is that number. +pub fn record_execution_peak_memory(peak_memory_kb: u64, instance_name: &str) { + EXECUTION_METRICS.execution_peak_memory.record( + peak_memory_sample(peak_memory_kb), + &[KeyValue::new(EXECUTION_INSTANCE, instance_name.to_string())], + ); +} + +/// Ceiling on a recorded peak-memory sample. +/// +/// Well above any real action and far below the point where a histogram's +/// `u64` sum can wrap, so it filters a garbage reading without touching a +/// plausible one. Everything past the largest bucket already shares the same +/// bucket, so this changes no bucket count. +const PEAK_MEMORY_MAX_BYTES: u64 = 1 << 50; // 1 PiB. + +/// Converts a worker's peak-memory reading to bytes, bounded. +/// +/// The figure crosses a gRPC boundary from a worker, so a malfunctioning one +/// could report something absurd. An unbounded value overflows the +/// histogram's `u64` sum, which panics a debug build and takes the thread +/// with it. Kept separate so it is directly testable: the overflow only +/// happens once a meter provider is installed, which no unit test does. +#[must_use] +pub fn peak_memory_sample(peak_memory_kb: u64) -> u64 { + peak_memory_kb + .saturating_mul(1024) + .min(PEAK_MEMORY_MAX_BYTES) } /// Helper function to create attributes for execution metrics @@ -651,3 +737,462 @@ pub fn make_execution_attributes( attrs } + +/// Records the histogram metrics derivable from a completed action's result. +pub fn record_completed_execution_metrics( + action_result: &ActionResult, + instance_name: &str, + worker_id: Option<&str>, + priority: Option, +) { + let m = &*EXECUTION_METRICS; + let md = &action_result.execution_metadata; + let base = make_execution_attributes(instance_name, worker_id, priority); + + let record_secs = + |hist: &metrics::Histogram, start: SystemTime, end: SystemTime, attrs: &[KeyValue]| { + if start > SystemTime::UNIX_EPOCH + && let Ok(d) = end.duration_since(start) + { + hist.record(d.as_secs_f64(), attrs); + } + }; + + // Queue wait (queued -> worker picked it up) and end-to-end duration. + record_secs( + &m.execution_queue_time, + md.queued_timestamp, + md.worker_start_timestamp, + &base, + ); + record_secs( + &m.execution_total_duration, + md.queued_timestamp, + md.worker_completed_timestamp, + &base, + ); + + // Per-phase stage durations, labeled by phase on the stage attribute. + for (phase, start, end) in [ + ( + "input_fetch", + md.input_fetch_start_timestamp, + md.input_fetch_completed_timestamp, + ), + ( + "execution", + md.execution_start_timestamp, + md.execution_completed_timestamp, + ), + ( + "output_upload", + md.output_upload_start_timestamp, + md.output_upload_completed_timestamp, + ), + ] { + let mut attrs = base.clone(); + attrs.push(KeyValue::new(EXECUTION_STAGE, phase)); + record_secs(&m.execution_stage_duration, start, end, &attrs); + } + + // Total bytes produced: output files plus stdout/stderr. + m.execution_output_size + .record(execution_output_bytes(action_result), &base); +} + +/// Total output bytes produced by an action: the output file digests plus the +/// stdout and stderr digests. +#[must_use] +pub fn execution_output_bytes(action_result: &ActionResult) -> u64 { + action_result + .output_files + .iter() + .map(|f| f.digest.size_bytes()) + .sum::() + + action_result.stdout_digest.size_bytes() + + action_result.stderr_digest.size_bytes() +} + +/// Global worker fleet metrics instruments. +pub static WORKER_METRICS: LazyLock = LazyLock::new(|| { + let meter = global::meter_with_scope(InstrumentationScope::builder("nativelink").build()); + + WorkerMetrics { + worker_connected_count: meter + .i64_up_down_counter("worker.connected.count") + .with_description("Number of workers currently connected to this scheduler instance") + .with_unit("{worker}") + .build(), + + worker_connections: meter + .u64_counter("worker.connections") + .with_description("Total number of workers that have joined the pool") + .with_unit("{worker}") + .build(), + + worker_disconnections: meter + .u64_counter("worker.disconnections") + .with_description("Total number of workers that have left the pool, by reason") + .with_unit("{worker}") + .build(), + + worker_keepalives: meter + .u64_counter("worker.keepalives") + .with_description("Total worker keepalives received") + .with_unit("{keepalive}") + .build(), + + worker_state_count: meter + .i64_up_down_counter("worker.state.count") + .with_description("Number of connected workers in each non-default state") + .with_unit("{worker}") + .build(), + } +}); + +/// Worker fleet metrics. +/// +/// These are per-scheduler-instance. A worker only appears in the registry of +/// the instance holding its stream, so with several schedulers behind a load +/// balancer the fleet total is the sum across instances, not any one of them. +/// +/// Deliberately not attributed by worker id. Ids are per connection, so a +/// fleet that churns would grow the label set without bound, and the +/// autoscaling and fleet-health questions these answer are all aggregate. +#[derive(Debug)] +pub struct WorkerMetrics { + /// Workers currently connected. + pub worker_connected_count: metrics::UpDownCounter, + /// Workers that have joined, cumulative. + pub worker_connections: metrics::Counter, + /// Workers that have left, cumulative, by reason. + pub worker_disconnections: metrics::Counter, + /// Keepalives received, cumulative. + pub worker_keepalives: metrics::Counter, + /// Connected workers currently paused or draining. + pub worker_state_count: metrics::UpDownCounter, +} + +/// Records a worker joining the pool. +pub fn record_worker_connected() { + WORKER_METRICS.worker_connected_count.add(1, &[]); + WORKER_METRICS.worker_connections.add(1, &[]); +} + +/// Records a worker leaving the pool. +/// +/// `was_draining` and `was_paused` unwind the state gauges, which would +/// otherwise keep counting a worker that is already gone. +pub fn record_worker_disconnected( + reason: WorkerDisconnectReason, + was_draining: bool, + was_paused: bool, +) { + WORKER_METRICS.worker_connected_count.add(-1, &[]); + WORKER_METRICS.worker_disconnections.add( + 1, + &[KeyValue::new(WORKER_DISCONNECT_REASON, reason.as_str())], + ); + if was_draining { + record_worker_state("draining", false); + } + if was_paused { + record_worker_state("paused", false); + } +} + +/// Records a worker entering or leaving `state`. +pub fn record_worker_state(state: &'static str, entered: bool) { + WORKER_METRICS.worker_state_count.add( + if entered { 1 } else { -1 }, + &[KeyValue::new(WORKER_STATE, state)], + ); +} + +/// Records a keepalive from a worker. +pub fn record_worker_keepalive() { + WORKER_METRICS.worker_keepalives.add(1, &[]); +} + +/// Global gRPC serving metrics. +/// +/// One duration histogram covers rate, errors and latency: the count gives +/// rate, the status attribute separates errors, and the buckets give latency. +pub static RPC_METRICS: LazyLock = LazyLock::new(|| { + let meter = global::meter_with_scope(InstrumentationScope::builder("nativelink").build()); + + RpcMetrics { + rpc_server_duration: meter + .f64_histogram("rpc.server.duration") + .with_description("Duration of inbound gRPC calls in seconds") + .with_unit("s") + .with_boundaries(vec![ + 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0, 60.0, + 300.0, + ]) + .build(), + } +}); + +/// gRPC serving metrics. +#[derive(Debug)] +pub struct RpcMetrics { + /// Duration of inbound gRPC calls, by service, method and status. + pub rpc_server_duration: metrics::Histogram, +} + +/// Records a served gRPC call. +/// +/// `full_path` is the HTTP path tonic routes on, `/package.Service/Method`. +pub fn record_rpc_served(full_path: &str, grpc_status: i32, duration_secs: f64) { + let (service, method) = split_grpc_path(full_path); + RPC_METRICS.rpc_server_duration.record( + duration_secs, + &[ + KeyValue::new(RPC_SERVICE, service.to_string()), + KeyValue::new(RPC_METHOD, method.to_string()), + KeyValue::new(RPC_STATUS_CODE, i64::from(grpc_status)), + ], + ); +} + +/// Splits `/package.Service/Method` into its service and method halves. +/// +/// Anything that does not look like a gRPC path is reported whole under an +/// `unknown` method, so an unexpected route still shows up rather than +/// silently vanishing. Both halves come from the route table, not user input, +/// so the label set stays bounded. +#[must_use] +pub fn split_grpc_path(full_path: &str) -> (&str, &str) { + let trimmed = full_path.strip_prefix('/').unwrap_or(full_path); + trimmed + .split_once('/') + .map_or((trimmed, "unknown"), |(service, method)| (service, method)) +} + +/// Global scheduler metrics. +pub static SCHEDULER_METRICS: LazyLock = LazyLock::new(|| { + let meter = global::meter_with_scope(InstrumentationScope::builder("nativelink").build()); + + SchedulerOtlpMetrics { + matching_duration: meter + .f64_histogram("scheduler.matching.duration") + .with_description("Duration of one queued-action to worker matching pass in seconds") + .with_unit("s") + .with_boundaries(vec![ + 0.0001, 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, + ]) + .build(), + + matching_passes: meter + .u64_counter("scheduler.matching.passes") + .with_description("Matching passes run, by result") + .with_unit("{pass}") + .build(), + } +}); + +/// Scheduler matching metrics. +/// +/// Named to avoid colliding with the existing `#[metric]` component struct of +/// the same idea in the scheduler crate. +#[derive(Debug)] +pub struct SchedulerOtlpMetrics { + /// How long a matching pass takes. The saturation signal: this climbing + /// while the queue is non-empty means matching is the bottleneck. + pub matching_duration: metrics::Histogram, + /// Matching passes, by result. + pub matching_passes: metrics::Counter, +} + +/// Records a completed matching pass. +pub fn record_matching_pass(duration_secs: f64, succeeded: bool) { + SCHEDULER_METRICS + .matching_duration + .record(duration_secs, &[]); + SCHEDULER_METRICS.matching_passes.add( + 1, + &[KeyValue::new( + SCHEDULER_MATCH_RESULT, + if succeeded { "ok" } else { "error" }, + )], + ); +} + +/// Global tiered-store metrics. +pub static STORE_TIER_METRICS: LazyLock = LazyLock::new(|| { + let meter = global::meter_with_scope(InstrumentationScope::builder("nativelink").build()); + + StoreTierMetrics { + tier_operations: meter + .u64_counter("store.tier.operations") + .with_description("Reads served by each tier of a tiered store, by result") + .with_unit("{operation}") + .build(), + + tier_io: meter + .u64_counter("store.tier.io") + .with_description("Bytes moved through each tier of a tiered store") + .with_unit("By") + .build(), + } +}); + +/// Tiered-store metrics. The hit ratio is `tier_operations{result="hit"}` over +/// the sum, which is the number worth alerting on for a fast/slow store. +#[derive(Debug)] +pub struct StoreTierMetrics { + /// Reads served per tier, by result. + pub tier_operations: metrics::Counter, + /// Bytes moved per tier and direction. + pub tier_io: metrics::Counter, +} + +/// Records a read served, or not served, by a tier. +pub fn record_store_tier_read(tier: &'static str, result: &'static str) { + STORE_TIER_METRICS.tier_operations.add( + 1, + &[ + KeyValue::new(STORE_TIER, tier), + KeyValue::new(STORE_RESULT, result), + ], + ); +} + +/// Records bytes moved through a tier. +pub fn record_store_tier_io(tier: &'static str, direction: &'static str, bytes: u64) { + STORE_TIER_METRICS.tier_io.add( + bytes, + &[ + KeyValue::new(STORE_TIER, tier), + KeyValue::new(STORE_DIRECTION, direction), + ], + ); +} + +/// Global health-check metrics. +pub static HEALTH_METRICS: LazyLock = LazyLock::new(|| { + let meter = global::meter_with_scope(InstrumentationScope::builder("nativelink").build()); + + HealthMetrics { + health_checks: meter + .u64_counter("health.checks") + .with_description("Health check results, by component and status") + .with_unit("{check}") + .build(), + } +}); + +/// Health-check metrics. +#[derive(Debug)] +pub struct HealthMetrics { + /// Health check results, by namespace and status. + pub health_checks: metrics::Counter, +} + +/// Records one component's health check result. +pub fn record_health_check(namespace: &str, status: &'static str) { + HEALTH_METRICS.health_checks.add( + 1, + &[ + KeyValue::new(HEALTH_NAMESPACE, namespace.to_string()), + KeyValue::new(HEALTH_STATUS, status), + ], + ); +} + +/// Global connection-pool metrics. +pub static CONNECTION_METRICS: LazyLock = LazyLock::new(|| { + let meter = global::meter_with_scope(InstrumentationScope::builder("nativelink").build()); + + ConnectionMetrics { + pool_available: meter + .u64_histogram("connection.pool.available") + .with_description("Free slots in a connection pool, sampled when one is taken") + .with_unit("{connection}") + .with_boundaries(vec![ + 0.0, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, + ]) + .build(), + + pool_acquisitions: meter + .u64_counter("connection.pool.acquisitions") + .with_description("Connection acquisitions, by pool and whether one was free") + .with_unit("{acquisition}") + .build(), + + reconnects: meter + .u64_counter("connection.reconnects") + .with_description("Reconnects performed, by pool") + .with_unit("{reconnect}") + .build(), + } +}); + +/// Connection-pool metrics. +/// +/// `pool_available` is the saturation signal: a pool that keeps reporting zero +/// free slots is the bottleneck, whatever the latency elsewhere says. Counting +/// queued acquisitions gives the same answer from the other direction. +#[derive(Debug)] +pub struct ConnectionMetrics { + /// Free slots at the moment a connection was taken. + pub pool_available: metrics::Histogram, + /// Acquisitions, by pool and result. + pub pool_acquisitions: metrics::Counter, + /// Reconnects, by pool. + pub reconnects: metrics::Counter, +} + +/// Ceiling on a recorded free-slot count. +/// +/// An unbounded pool is a semaphore holding `Semaphore::MAX_PERMITS`, around +/// 2.3e18. Recording that overflows the histogram's `u64` sum after a handful +/// of samples, which panics a debug build. Callers pass `None` for an +/// unbounded pool, and this clamp is the backstop if one ever does not: it +/// sits above the largest bucket boundary, so bucket counts are unchanged. +const POOL_AVAILABLE_MAX: u64 = 1024; + +/// Records a connection being taken from `pool`. +/// +/// `available` is the free-slot count, or `None` when the pool is unbounded +/// and the figure would be meaningless. `queued` means nothing was free and +/// the caller had to wait, which is the case worth alerting on. +/// Clamps a free-slot count to something a histogram can accumulate. +/// +/// Kept separate so it is directly testable: the failure this guards against +/// only appears once a meter provider is installed, so a test that merely +/// calls `record_connection_acquired` cannot catch it. +#[must_use] +pub fn pool_available_sample(available: usize) -> u64 { + u64::try_from(available) + .unwrap_or(POOL_AVAILABLE_MAX) + .min(POOL_AVAILABLE_MAX) +} + +pub fn record_connection_acquired(pool: &'static str, available: Option, queued: bool) { + if let Some(available) = available { + CONNECTION_METRICS.pool_available.record( + pool_available_sample(available), + &[KeyValue::new(CONNECTION_POOL, pool)], + ); + } + CONNECTION_METRICS.pool_acquisitions.add( + 1, + &[ + KeyValue::new(CONNECTION_POOL, pool), + KeyValue::new( + CONNECTION_RESULT, + if queued { "queued" } else { "immediate" }, + ), + ], + ); +} + +/// Records a reconnect. A rising count means the backend is flapping, which +/// on Redis usually means a failover. +pub fn record_connection_reconnect(pool: &'static str) { + CONNECTION_METRICS + .reconnects + .add(1, &[KeyValue::new(CONNECTION_POOL, pool)]); +} diff --git a/nativelink-util/src/origin_event.rs b/nativelink-util/src/origin_event.rs index 723697bfa..4cb85636a 100644 --- a/nativelink-util/src/origin_event.rs +++ b/nativelink-util/src/origin_event.rs @@ -16,6 +16,7 @@ use std::sync::OnceLock; use base64::Engine; use base64::prelude::BASE64_STANDARD_NO_PAD; +use nativelink_error::Error; use nativelink_proto::build::bazel::remote::execution::v2::RequestMetadata; use nativelink_proto::com::github::trace_machina::nativelink::events::{ Event, event, request_event, response_event, stream_event, @@ -34,11 +35,11 @@ pub fn request_metadata_to_baggage(metadata: &RequestMetadata) -> String { BASE64_STANDARD_NO_PAD.encode(metadata.encode_to_vec()) } -pub fn request_metadata_from_baggage(value: &str) -> Result { +pub fn request_metadata_from_baggage(value: &str) -> Result { let decoded = BASE64_STANDARD_NO_PAD .decode(value.as_bytes()) - .map_err(|err| prost::DecodeError::new(err.to_string()))?; - RequestMetadata::decode(&*decoded) + .map_err(Error::from)?; + RequestMetadata::decode(&*decoded).map_err(Error::from) } /// Returns a unique ID for the given event. @@ -144,7 +145,7 @@ where } } -#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct OriginMetadata { pub identity: String, #[serde( diff --git a/nativelink-util/src/proto_stream_utils.rs b/nativelink-util/src/proto_stream_utils.rs index b658168fc..dd021466c 100644 --- a/nativelink-util/src/proto_stream_utils.rs +++ b/nativelink-util/src/proto_stream_utils.rs @@ -89,6 +89,13 @@ where pub fn is_first_msg_complete(&self) -> bool { self.first_msg.as_ref().is_some_and(|msg| msg.finish_write) } + + fn enforce_wire_size_matches_digest_size(&self) -> bool { + matches!( + self.resource_info.compressor.as_deref(), + None | Some("identity") + ) + } } impl Stream for WriteRequestStreamWrapper @@ -102,12 +109,14 @@ where // If the stream said that the previous message was the last one, then // return a stream EOF (i.e. None). if self.write_finished { - error_if!( - self.bytes_received != self.resource_info.expected_size, - "Did not send enough data. Expected {}, but so far received {}", - self.resource_info.expected_size, - self.bytes_received - ); + if self.enforce_wire_size_matches_digest_size() { + error_if!( + self.bytes_received != self.resource_info.expected_size, + "Did not send enough data. Expected {}, but so far received {}", + self.resource_info.expected_size, + self.bytes_received + ); + } return Poll::Ready(None); } @@ -133,7 +142,9 @@ where self.bytes_received += message.data.len(); // Check that we haven't read past the expected end. - if self.bytes_received > self.resource_info.expected_size { + if self.enforce_wire_size_matches_digest_size() + && self.bytes_received > self.resource_info.expected_size + { Err(make_input_err!( "Sent too much data. Expected {}, but so far received {}", self.resource_info.expected_size, @@ -196,6 +207,10 @@ impl Stream for FirstStream { } } +/// Largest `data` payload in a single `ByteStream` `WriteRequest`, kept under +/// tonic's 4MiB default `max_decoding_message_size` with room to spare. +pub const MAX_WRITE_REQUEST_DATA_BYTES: usize = 2 * 1024 * 1024; + /// This structure wraps all of the information required to perform a write /// request on the `GrpcStore`. It stores the last message retrieved which allows /// the write to resume since the UUID allows upload resume at the server. @@ -216,6 +231,15 @@ where resume_queue: [Option; 2], // An optimisation to avoid having to manage resume_queue when it's empty. is_resumed: bool, + // Remainder of an incoming frame too large to forward in one message. + // Drained before the next frame is read so ordering is preserved. + pending: Option, + // When false, a partially-consumed stream never reports `can_resume()`: + // uploads whose server-side protocol cannot accept a replay from a + // nonzero offset (REAPI compressed-blobs writes) must fail fast instead + // of burning retries on guaranteed-rejected resumes. A stream that has + // not yet been consumed can always be retried from the start. + resumable: bool, } impl WriteState @@ -231,7 +255,45 @@ where cached_messages: [None, None], resume_queue: [None, None], is_resumed: false, + pending: None, + resumable: true, + } + } + + /// Caps the payload of an outgoing message, stashing anything over the + /// limit to be sent as the following message. + /// + /// A caller can hand us a whole blob in one frame, and forwarding that + /// verbatim produces a message the receiver rejects at its 4MiB default. + /// Only the final piece carries `finish_write`, and each piece advances + /// `write_offset` by what came before it. + fn split_oversized(&mut self, mut message: WriteRequest) -> WriteRequest { + if message.data.len() <= MAX_WRITE_REQUEST_DATA_BYTES { + return message; } + let rest = message.data.split_off(MAX_WRITE_REQUEST_DATA_BYTES); + let sent_len = i64::try_from(message.data.len()).unwrap_or(i64::MAX); + self.pending = Some(WriteRequest { + resource_name: message.resource_name.clone(), + write_offset: message.write_offset.saturating_add(sent_len), + finish_write: message.finish_write, + data: rest, + }); + message.finish_write = false; + message + } + + /// Marks this write as non-resumable: once the stream has been partially + /// consumed, `can_resume()` reports false so the caller fails fast with + /// the original error instead of replaying messages the server-side + /// protocol is guaranteed to reject. Retrying an unconsumed stream from + /// the start remains allowed. + pub const fn set_non_resumable(&mut self) { + self.resumable = false; + } + + pub(crate) const fn is_resumable(&self) -> bool { + self.resumable } fn push_message(&mut self, message: WriteRequest) { @@ -256,7 +318,8 @@ where pub const fn can_resume(&self) -> bool { self.read_stream_error.is_none() - && (self.cached_messages[0].is_some() || self.read_stream.is_first_msg()) + && ((self.resumable && self.cached_messages[0].is_some()) + || self.read_stream.is_first_msg()) } pub fn resume(&mut self) { @@ -308,6 +371,14 @@ where if cached_message.is_some() { return Poll::Ready(cached_message); } + // Finish draining an oversized frame before reading the next one. + if let Some(pending) = local_state.pending.take() { + let message = local_state.split_oversized(pending); + if local_state.is_resumable() { + local_state.push_message(message.clone()); + } + return Poll::Ready(Some(message)); + } // Read a new write request from the downstream. let Poll::Ready(maybe_message) = Pin::new(&mut local_state.read_stream).poll_next(cx) else { @@ -333,9 +404,13 @@ where } } } + let message = local_state.split_oversized(message); // Cache the last request in case there is an error to allow - // the upload to be resumed. - local_state.push_message(message.clone()); + // the upload to be resumed. Non-resumable writes skip the + // clone: cached messages would never be replayed. + if local_state.is_resumable() { + local_state.push_message(message.clone()); + } Some(message) } Some(Err(err)) => { diff --git a/nativelink-util/src/retry.rs b/nativelink-util/src/retry.rs index e87bc4196..1cd0ba9fb 100644 --- a/nativelink-util/src/retry.rs +++ b/nativelink-util/src/retry.rs @@ -100,31 +100,30 @@ impl Retrier { /// This should only return true if the error code should be interpreted as /// temporary. fn should_retry(&self, code: Code) -> bool { - if code == Code::Ok { - false - } else if let Some(retry_codes) = &self.config.retry_on_errors { + if let Some(retry_codes) = &self.config.retry_on_errors { retry_codes.contains(&to_error_code(code)) } else { + // Match is intentionally exhaustive: if a new `Code` variant is added, + // the compiler forces a decision here. New codes default to permanent + // (no retry) rather than silently being retried. match code { - // TODO(SchahinRohani): Handle all cases properly so there is no need for a wildcard match - // All cases where a retry should happen are commented out here and replaced with a wildcard match. - Code::InvalidArgument - | Code::FailedPrecondition - | Code::OutOfRange - | Code::Unimplemented + Code::Cancelled + | Code::Unknown + | Code::DeadlineExceeded + | Code::ResourceExhausted + | Code::Aborted + | Code::Internal + | Code::Unavailable + | Code::DataLoss => true, + Code::Ok + | Code::InvalidArgument | Code::NotFound | Code::AlreadyExists | Code::PermissionDenied + | Code::FailedPrecondition + | Code::OutOfRange + | Code::Unimplemented | Code::Unauthenticated => false, - // Code::Cancelled - // | Code::Unknown - // | Code::DeadlineExceeded - // | Code::ResourceExhausted - // | Code::Aborted - // | Code::Internal - // | Code::Unavailable - // | Code::DataLoss => true, - _ => true, } } } diff --git a/nativelink-util/src/store_trait.rs b/nativelink-util/src/store_trait.rs index 942d3a15c..5fb650e2b 100644 --- a/nativelink-util/src/store_trait.rs +++ b/nativelink-util/src/store_trait.rs @@ -401,10 +401,7 @@ impl Store { } #[inline] - pub fn register_remove_callback( - &self, - callback: Arc, - ) -> Result<(), Error> { + pub fn register_remove_callback(&self, callback: RemoveCallback) -> Result<(), Error> { self.inner.clone().register_remove_callback(callback) } } @@ -617,6 +614,8 @@ pub trait StoreLike: Send + Sync + Sized + Unpin + 'static { } } +pub type RemoveCallback = Arc; + #[async_trait] pub trait StoreDriver: Sync + Send + Unpin + MetricsComponent + HealthStatusIndicator + 'static @@ -865,10 +864,7 @@ pub trait StoreDriver: // Register health checks used to monitor the store. fn register_health(self: Arc, _registry: &mut HealthRegistryBuilder) {} - fn register_remove_callback( - self: Arc, - callback: Arc, - ) -> Result<(), Error>; + fn register_remove_callback(self: Arc, callback: RemoveCallback) -> Result<(), Error>; } // Callback to be called when a store deletes an item. This is used so diff --git a/nativelink-util/src/telemetry.rs b/nativelink-util/src/telemetry.rs index 527d8473d..3565e3875 100644 --- a/nativelink-util/src/telemetry.rs +++ b/nativelink-util/src/telemetry.rs @@ -47,6 +47,7 @@ use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{EnvFilter, Layer, Registry, fmt, registry}; use uuid::Uuid; +use crate::metrics::record_rpc_served; use crate::origin_event::{BAZEL_METADATA_KEY, request_metadata_to_baggage}; /// The OTLP "service.name" field for all nativelink services. @@ -118,7 +119,7 @@ pub async fn init_tracing() -> Result<(), nativelink_error::Error> { // We currently use a UUIDv4 for "service.instance.id" as per: // https://opentelemetry.io/docs/specs/semconv/attributes-registry/service/ - // This might change as we get a better understanding of its usecases in the + // This might change as we get a better understanding of its use cases in the // context of broader observability infrastructure. let resource = Resource::builder() .with_service_name(NATIVELINK_SERVICE_NAME) @@ -246,8 +247,7 @@ pub async fn maybe_load_balanced_channel() -> Option { } } /// This is the header that bazel sends when using the `--remote_header` flag. -/// TODO(palfrey): There are various other headers that bazel supports. -/// Optimize their usage. +/// TODO(palfrey): Bazel supports other headers, and we should optimize their usage. const BAZEL_REQUESTMETADATA_HEADER: &str = "build.bazel.remote.execution.v2.requestmetadata-bin"; use opentelemetry::baggage::BaggageExt; @@ -297,7 +297,7 @@ where fn call(&mut self, req: hyper::http::Request) -> Self::Future { // We must take the current `inner` and not the clone. - // See: https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services + // See: let clone = self.inner.clone(); let mut inner = core::mem::replace(&mut self.inner, clone); @@ -365,10 +365,38 @@ NativeLink instance configured to require this OpenTelemetry Baggage header: } let cx = cx.with_value(client_headers); - Box::pin(async move { inner.call(req).with_context(cx).await }) + // Rate, errors and latency for every gRPC service, taken here because + // this layer already wraps all of them. + let route = req.uri().path().to_string(); + let started = std::time::Instant::now(); + Box::pin(async move { + let result = inner.call(req).with_context(cx).await; + if let Ok(response) = &result { + record_rpc_served( + &route, + grpc_status_of(response.headers()), + started.elapsed().as_secs_f64(), + ); + } + result + }) } } +/// Reads the gRPC status from a response. +/// +/// Tonic puts `grpc-status` in the headers when it fails before streaming and +/// in the trailers otherwise. Trailers are not available here without +/// consuming the body, so a call that got far enough to stream is reported as +/// OK. Transport-level failures never reach this point at all. +fn grpc_status_of(headers: &hyper::http::HeaderMap) -> i32 { + headers + .get("grpc-status") + .and_then(|value| value.to_str().ok()) + .and_then(|value| value.parse::().ok()) + .unwrap_or(0) +} + #[derive(Debug, Clone, Copy)] pub struct OtlpLayer { identity_required: bool, diff --git a/nativelink-util/src/wire_compression.rs b/nativelink-util/src/wire_compression.rs new file mode 100644 index 000000000..c9760c7ea --- /dev/null +++ b/nativelink-util/src/wire_compression.rs @@ -0,0 +1,349 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Zstd wire-compression codecs for REAPI compressed-blobs. +//! +//! Shared by the server-side accept/serve paths (nativelink-service) and the +//! client-side `GrpcStore` transfers (nativelink-store). This is orthogonal +//! to at-rest compression (`CompressionStore` with LZ4). + +use std::io::Read; + +use bytes::Bytes; +use nativelink_error::{Code, Error, ResultExt, make_err, make_input_err}; +use nativelink_proto::build::bazel::remote::execution::v2::compressor; + +use crate::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; +use crate::common::DigestInfo; +use crate::digest_hasher::{DigestHasher, DigestHasherFunc}; + +/// Zstd compression level for wire compression. +/// Level 0 in the zstd crate means "use default" (currently 3). +/// We use an explicit level for clarity. +pub const ZSTD_COMPRESSION_LEVEL: i32 = 3; + +/// Upper bound on the buffer `decompress` reserves up front for a zstd blob. +/// `expected_size` comes from the client's claimed digest, so it must never be +/// used as an allocation hint directly: a small payload claiming a huge size +/// would otherwise force a large pre-emptive allocation before the real +/// decompressed length is ever known. We reserve `min(expected_size, this)` +/// so common payloads never reallocate while a hostile claim allocates at most +/// this. Sized comfortably above any honest `BatchUpdateBlobs` payload (the +/// only caller of this bulk path; large blobs stream through `ByteStream`). +const ZSTD_DECOMPRESS_PREALLOC_CAP: usize = 1024 * 1024; + +/// Compress data using the specified wire compressor. +/// +/// `data` is the raw (uncompressed) bytes from the store. +/// Returns the compressed bytes suitable for sending on the wire. +pub fn compress(data: Bytes, compressor_value: compressor::Value) -> Result { + match compressor_value { + compressor::Value::Identity => Ok(data), + compressor::Value::Zstd => { + let compressed = zstd::bulk::compress(&data, ZSTD_COMPRESSION_LEVEL) + .map_err(|e| make_err!(Code::Internal, "Zstd compression failed: {}", e))?; + Ok(Bytes::from(compressed)) + } + _ => Err(make_input_err!( + "Unsupported wire compressor for compression: {:?}", + compressor_value + )), + } +} + +/// Decompress data using the specified wire compressor. +/// +/// `data` is the compressed bytes received from the wire. +/// `expected_size` is the uncompressed size (from the client's digest). It is +/// the hard cap on the decompressed output, but never a direct allocation +/// hint: the buffer grows with the real decoded bytes so a small payload +/// claiming a huge size cannot force a large up-front allocation. +/// Returns the decompressed bytes suitable for storing. +pub fn decompress( + data: &[u8], + compressor_value: compressor::Value, + expected_size: usize, +) -> Result { + match compressor_value { + compressor::Value::Identity => { + if data.len() != expected_size { + return Err(make_err!( + Code::InvalidArgument, + "Identity data size {} does not match expected size {}", + data.len(), + expected_size + )); + } + Ok(Bytes::copy_from_slice(data)) + } + compressor::Value::Zstd => { + // Decode incrementally so `expected_size` (which is attacker + // controlled — it is the client's claimed digest size) can bound + // the output without being trusted as an allocation size. We + // reserve only `min(expected_size, ZSTD_DECOMPRESS_PREALLOC_CAP)`, + // then `take(expected_size + 1)` hard-caps the decoder so a + // decompression bomb is rejected as soon as it overshoots. This + // mirrors the real-byte-count validation the identity arm and the + // streaming upload path already perform. + let decoder = zstd::stream::read::Decoder::new(data) + .map_err(|e| make_err!(Code::InvalidArgument, "Zstd decompression failed: {e}"))?; + let mut output = Vec::with_capacity(expected_size.min(ZSTD_DECOMPRESS_PREALLOC_CAP)); + // `+ 1` lets an oversized stream produce one byte past the cap so + // the size check below rejects it rather than silently truncating. + let cap = u64::try_from(expected_size) + .err_tip(|| "expected_size did not fit in u64")? + .saturating_add(1); + decoder + .take(cap) + .read_to_end(&mut output) + .map_err(|e| make_err!(Code::InvalidArgument, "Zstd decompression failed: {e}"))?; + if output.len() != expected_size { + return Err(make_err!( + Code::InvalidArgument, + "Decompressed size {} does not match expected size {}", + output.len(), + expected_size + )); + } + Ok(Bytes::from(output)) + } + _ => Err(make_input_err!( + "Unsupported wire compressor for decompression: {:?}", + compressor_value + )), + } +} + +/// Decode a client's zstd wire stream into raw bytes on `tx`, asynchronously. +/// +/// Like [`stream_encode_compressed_download`], this must not occupy a tokio +/// blocking-pool thread for the stream's lifetime: the input arrives at the +/// client's upload pace and `tx` drains at the store's write pace, so a +/// blocking implementation parks a pool thread on whichever side is slower +/// for as long as the upload lasts. The zstd frame is consumed incrementally +/// with the raw streaming API instead; per-chunk decode cost is bounded by +/// the channel chunk size, so it runs inline on the async runtime with +/// channel-native backpressure on both sides. +/// +/// Validation semantics match the REAPI compressed-blobs contract: the +/// decoded byte count may never exceed the digest size (checked per chunk so +/// a decompression bomb is rejected as soon as it overshoots), the final +/// count must equal it exactly, and the decoded bytes must hash to `digest`. +pub async fn stream_decode_compressed_upload( + mut compressed_rx: DropCloserReadHalf, + wire_compressor: compressor::Value, + digest: DigestInfo, + digest_function: DigestHasherFunc, + mut tx: DropCloserWriteHalf, +) -> Result<(), Error> { + use zstd::stream::raw::{Decoder, InBuffer, Operation, OutBuffer}; + + if wire_compressor != compressor::Value::Zstd { + return Err(make_input_err!( + "Streaming upload decompression only supports zstd, got {:?}", + wire_compressor + )); + } + + let expected_size = digest.size_bytes(); + let mut hasher = digest_function.hasher(); + let mut decoded_size = 0u64; + let mut decoder = Decoder::new() + .map_err(|e| make_err!(Code::InvalidArgument, "Zstd decompression failed: {}", e))?; + // `DCtx::out_size()` guarantees a full decompressed block always fits, so + // the decoder never stalls for lack of output space within one `run`. + let mut out_buf = vec![0u8; zstd::zstd_safe::DCtx::out_size()]; + // Last input-size hint from the decoder: nonzero at input EOF means the + // stream ended in the middle of a frame and must be rejected. + let mut frame_input_hint = 0usize; + loop { + let chunk = compressed_rx + .recv() + .await + .err_tip(|| "Failed to receive compressed data in stream_decode_compressed_upload")?; + if chunk.is_empty() { + break; // EOF. + } + let mut in_buffer = InBuffer::around(&chunk); + loop { + let mut out_buffer = OutBuffer::around(out_buf.as_mut_slice()); + frame_input_hint = decoder.run(&mut in_buffer, &mut out_buffer).map_err(|e| { + make_err!(Code::InvalidArgument, "Zstd decompression failed: {}", e) + })?; + let produced = Bytes::copy_from_slice(out_buffer.as_slice()); + // A completely full output buffer means the decoder may still + // have buffered output to flush, even with no input left. + let output_was_full = produced.len() == out_buf.len(); + if !produced.is_empty() { + let produced_u64 = u64::try_from(produced.len()) + .err_tip(|| "Decoded chunk size was not convertible to u64")?; + decoded_size = decoded_size.checked_add(produced_u64).ok_or_else(|| { + make_err!( + Code::InvalidArgument, + "Decoded compressed upload size overflow" + ) + })?; + if decoded_size > expected_size { + return Err(make_err!( + Code::InvalidArgument, + "Decoded compressed upload size {} bytes exceeds digest size {} bytes", + decoded_size, + expected_size + )); + } + hasher.update(&produced); + tx.send(produced).await?; + } + // `hint == 0` means the frame is completely decoded AND fully + // flushed. It must terminate the loop even when the output + // buffer was filled exactly: polling the decoder again after + // frame end would return the input-size hint for a NEW frame + // header, and the post-EOF `frame_input_hint != 0` check would + // then misreport a fully-decoded stream as truncated. This is + // deterministic for blobs whose decompressed size is an exact + // multiple of the decoder output buffer size. + if in_buffer.pos() == in_buffer.src.len() && (frame_input_hint == 0 || !output_was_full) + { + break; + } + } + } + if frame_input_hint != 0 { + return Err(make_err!( + Code::InvalidArgument, + "Compressed upload stream ended in the middle of a zstd frame" + )); + } + + if decoded_size != expected_size { + return Err(make_err!( + Code::InvalidArgument, + "Decompressed size {} does not match expected size {}", + decoded_size, + expected_size + )); + } + let actual_digest = hasher.finalize_digest(); + if actual_digest != digest { + return Err(make_err!( + Code::InvalidArgument, + "Decompressed digest {} does not match expected digest {}", + actual_digest, + digest + )); + } + + tx.send_eof() + .err_tip(|| "Failed to send decompressed upload EOF")?; + Ok(()) +} + +/// Encode a raw byte stream into a single zstd frame on `tx`, asynchronously. +/// +/// This runs entirely on the async runtime and must never occupy a tokio +/// blocking-pool thread for the stream's lifetime: `tx` drains at the gRPC +/// client's pace, so a blocking implementation (blocking reads from `raw_rx` +/// plus `blocking_send` into `tx`) parks one pool thread per concurrent +/// compressed download until the client finishes. Enough concurrent downloads +/// with slow consumers then exhaust the blocking pool and starve every other +/// `spawn_blocking` user (filesystem store I/O, upload decode, credential +/// resolution). The zstd frame is instead produced incrementally with the raw +/// streaming API: the CPU cost per iteration is bounded by the channel chunk +/// size (small — micro/milliseconds), so it is acceptable inline on a worker +/// thread, and `tx.send(...).await` gives backpressure without a parked +/// thread. +/// +/// The output is one well-formed zstd frame, identical in wire format to what +/// `zstd::stream::read::Encoder` produces (both drive `ZSTD_compressStream` +/// on a fresh `CCtx`). +pub async fn stream_encode_compressed_download( + mut raw_rx: DropCloserReadHalf, + wire_compressor: compressor::Value, + compression_level: i32, + tx: DropCloserWriteHalf, +) -> Result<(), Error> { + stream_encode_compressed_download_from_reader( + &mut raw_rx, + wire_compressor, + compression_level, + tx, + ) + .await +} + +/// Encode a raw byte stream into a single zstd frame, borrowing the input +/// reader so a caller can continue draining it if the downstream consumer +/// finishes before the encoder does. +pub async fn stream_encode_compressed_download_from_reader( + raw_rx: &mut DropCloserReadHalf, + wire_compressor: compressor::Value, + compression_level: i32, + mut tx: DropCloserWriteHalf, +) -> Result<(), Error> { + use zstd::stream::raw::{Encoder, InBuffer, Operation, OutBuffer}; + + if wire_compressor != compressor::Value::Zstd { + return Err(make_input_err!( + "Streaming download compression only supports zstd, got {:?}", + wire_compressor + )); + } + + let mut encoder = Encoder::new(compression_level) + .map_err(|e| make_err!(Code::Internal, "Zstd compression failed: {}", e))?; + // `CCtx::out_size()` guarantees a full compressed block always fits, so + // the encoder never stalls for lack of output space within one `run`. + let mut out_buf = vec![0u8; zstd::zstd_safe::CCtx::out_size()]; + loop { + let chunk = raw_rx + .recv() + .await + .err_tip(|| "Failed to receive raw data in stream_encode_compressed_download")?; + if chunk.is_empty() { + break; // EOF. + } + let mut in_buffer = InBuffer::around(&chunk); + while in_buffer.pos() < in_buffer.src.len() { + let mut out_buffer = OutBuffer::around(out_buf.as_mut_slice()); + encoder + .run(&mut in_buffer, &mut out_buffer) + .map_err(|e| make_err!(Code::Internal, "Zstd compression failed: {}", e))?; + let produced = out_buffer.as_slice(); + if !produced.is_empty() { + tx.send(Bytes::copy_from_slice(produced)).await?; + } + } + } + + // Finish the frame: flush any internally buffered compressed data plus + // the frame epilogue. `finish` reports the bytes still pending, so loop + // until it reports none. + loop { + let mut out_buffer = OutBuffer::around(out_buf.as_mut_slice()); + let remaining = encoder + .finish(&mut out_buffer, true) + .map_err(|e| make_err!(Code::Internal, "Zstd compression failed: {}", e))?; + let produced = out_buffer.as_slice(); + if !produced.is_empty() { + tx.send(Bytes::copy_from_slice(produced)).await?; + } + if remaining == 0 { + break; + } + } + + tx.send_eof() + .err_tip(|| "Failed to send compressed download EOF")?; + Ok(()) +} diff --git a/nativelink-util/tests/action_messages_test.rs b/nativelink-util/tests/action_messages_test.rs index f295ca08d..963414a34 100644 --- a/nativelink-util/tests/action_messages_test.rs +++ b/nativelink-util/tests/action_messages_test.rs @@ -66,7 +66,7 @@ fn make_missing_blob_error(digest: &DigestInfo) -> Error { ) .with_context(ErrorContext::MissingDigest { hash: digest.packed_hash().to_string(), - size: digest.size_bytes() as i64, + size: digest.size_bytes().try_into().unwrap_or(i64::MAX), }) } diff --git a/nativelink-util/tests/evicting_map_test.rs b/nativelink-util/tests/evicting_map_test.rs index 769000dea..e63ada807 100644 --- a/nativelink-util/tests/evicting_map_test.rs +++ b/nativelink-util/tests/evicting_map_test.rs @@ -166,6 +166,399 @@ async fn insert_purges_at_max_bytes() -> Result<(), Error> { Ok(()) } +#[nativelink_test] +async fn leased_key_survives_fast_tier_pressure_until_released() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 1, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let leased_key = DigestInfo::try_new(HASH1, 0)?; + let other_key = DigestInfo::try_new(HASH2, 0)?; + + // Reserve the key before it is populated. This is the ordering used by an + // action input lease and is the race the regression test protects. + evicting_map.lease_key(leased_key); + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + evicting_map + .insert(other_key, Bytes::from(DATA).into()) + .await; + + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + Some(DATA.len() as u64), + "leased input must remain available while another blob is inserted", + ); + assert_eq!( + evicting_map.size_for_key(&other_key).await, + None, + "unleased blob should be the eviction candidate", + ); + + evicting_map.release_key(&leased_key).await; + evicting_map + .insert(other_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + None, + "released input may be evicted after its action completes", + ); + + Ok(()) +} + +#[nativelink_test] +async fn all_leased_entries_can_temporarily_exceed_capacity() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 1, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let first_key = DigestInfo::try_new(HASH1, 0)?; + let second_key = DigestInfo::try_new(HASH2, 0)?; + + // With no evictable victim, pressure insertion must not evict active + // inputs just to satisfy max_count. + evicting_map.lease_key(first_key); + evicting_map.lease_key(second_key); + evicting_map + .insert(first_key, Bytes::from(DATA).into()) + .await; + evicting_map + .insert(second_key, Bytes::from(DATA).into()) + .await; + assert_eq!(evicting_map.len_for_test(), 2); + assert!(logs_contain( + "Eviction requested, but every resident entry is leased" + )); + + // Releasing one lease makes the retained entry an ordinary victim again. + evicting_map.release_key(&first_key).await; + assert_eq!( + evicting_map.size_for_key(&first_key).await, + None, + "released entry should be trimmed once an unleased victim exists", + ); + assert_eq!( + evicting_map.size_for_key(&second_key).await, + Some(DATA.len() as u64), + "the still-leased entry must remain available", + ); + + Ok(()) +} + +#[nativelink_test] +async fn removing_leased_key_preserves_lease_until_release() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 1, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let leased_key = DigestInfo::try_new(HASH1, 0)?; + let other_key = DigestInfo::try_new(HASH2, 0)?; + + // Explicit removal deletes the resident value but intentionally leaves + // the lease active so a subsequent population cannot race with eviction. + evicting_map.lease_key(leased_key); + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + assert!(evicting_map.remove(&leased_key).await); + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + Some(DATA.len() as u64), + "reinserted leased value must remain resident", + ); + + // The final release must clear the lease even when the key was removed + // and repopulated while the lease was active. + evicting_map.release_key(&leased_key).await; + evicting_map + .insert(other_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + None, + "reinserted value should become evictable after release", + ); + assert_eq!( + evicting_map.size_for_key(&other_key).await, + Some(DATA.len() as u64), + ); + + Ok(()) +} + +#[nativelink_test] +async fn evictable_lru_tracks_unleased_access() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 3, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let first_key = DigestInfo::try_new(HASH1, 0)?; + let leased_key = DigestInfo::try_new(HASH2, 0)?; + let third_key = DigestInfo::try_new(HASH3, 0)?; + let fourth_key = DigestInfo::try_new(HASH4, 0)?; + + evicting_map + .insert(first_key, Bytes::from(DATA).into()) + .await; + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + evicting_map + .insert(third_key, Bytes::from(DATA).into()) + .await; + + // Removing a key from the evictable index must not make the next + // unleased insertion scan or evict the active input. + evicting_map.lease_key(leased_key); + // A normal read promotes both indexes. If only the resident LRU were + // updated, `first_key` would be selected instead of `third_key`. + assert_eq!( + evicting_map.get(&first_key).await, + Some(Bytes::from(DATA).into()) + ); + evicting_map + .insert(fourth_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&first_key).await, + Some(DATA.len() as u64), + "an unleased read must promote the evictable LRU as well", + ); + assert_eq!( + evicting_map.size_for_key(&third_key).await, + None, + "the least-recently used unleased entry should be evicted", + ); + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + Some(DATA.len() as u64), + "leased entries are never eviction candidates", + ); + + Ok(()) +} + +#[nativelink_test] +async fn remove_if_tracks_unleased_access() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 3, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let first_key = DigestInfo::try_new(HASH1, 0)?; + let second_key = DigestInfo::try_new(HASH2, 0)?; + let third_key = DigestInfo::try_new(HASH3, 0)?; + let fourth_key = DigestInfo::try_new(HASH4, 0)?; + + for key in [first_key, second_key, third_key] { + evicting_map.insert(key, Bytes::from(DATA).into()).await; + } + assert!( + !evicting_map.remove_if(&first_key, |_| false).await, + "the conditional removal should leave the entry resident", + ); + evicting_map + .insert(fourth_key, Bytes::from(DATA).into()) + .await; + + assert_eq!( + evicting_map.size_for_key(&first_key).await, + Some(DATA.len() as u64), + "remove_if must promote the evictable LRU with the resident LRU", + ); + assert_eq!( + evicting_map.size_for_key(&second_key).await, + None, + "the least-recently used unleased entry should be evicted", + ); + + Ok(()) +} + +#[nativelink_test] +async fn released_lease_reenters_evictable_lru_as_mru() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 2, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let older_key = DigestInfo::try_new(HASH1, 0)?; + let leased_key = DigestInfo::try_new(HASH2, 0)?; + let resident_key = DigestInfo::try_new(HASH3, 0)?; + + evicting_map + .insert(older_key, Bytes::from(DATA).into()) + .await; + evicting_map.lease_key(leased_key); + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + evicting_map + .insert(resident_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&older_key).await, + None, + "the ordinary unleased entry should be evicted while the lease is active", + ); + + // Releasing a resident key re-enters the candidate index as MRU. The + // existing unleased `resident_key` is therefore evicted before the just-released + // key when another item creates pressure. + evicting_map.release_key(&leased_key).await; + evicting_map + .insert(older_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + Some(DATA.len() as u64), + "a released key should re-enter as MRU", + ); + assert_eq!( + evicting_map.size_for_key(&resident_key).await, + None, + "older unleased entries should be evicted before a just-released key", + ); + + Ok(()) +} + +#[nativelink_test] +async fn leased_key_batch_release_preserves_reference_counts() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 1, + max_seconds: 0, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let leased_key = DigestInfo::try_new(HASH1, 0)?; + let other_key = DigestInfo::try_new(HASH2, 0)?; + + // Three references let the batch release exercise both duplicate keys and + // the remaining reference-counted lease. + evicting_map.lease_key(leased_key); + evicting_map.lease_key(leased_key); + evicting_map.lease_key(leased_key); + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + evicting_map.release_keys([&leased_key, &leased_key]).await; + + evicting_map + .insert(other_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + Some(DATA.len() as u64), + "one remaining lease must keep the input available", + ); + assert_eq!( + evicting_map.size_for_key(&other_key).await, + None, + "unleased pressure entry should be evicted first", + ); + + evicting_map.release_keys([&leased_key]).await; + evicting_map + .insert(other_key, Bytes::from(DATA).into()) + .await; + assert_eq!( + evicting_map.size_for_key(&leased_key).await, + None, + "the final release must re-enable normal eviction", + ); + + Ok(()) +} + +#[nativelink_test] +async fn leased_key_survives_ttl_until_released() -> Result<(), Error> { + const DATA: &str = "12345678"; + let evicting_map = EvictingMap::::new( + &EvictionPolicy { + max_count: 0, + max_seconds: 5, + max_bytes: 0, + evict_bytes: 0, + }, + MockInstantWrapped::default(), + ); + let leased_key = DigestInfo::try_new(HASH1, 0)?; + + evicting_map.lease_key(leased_key); + evicting_map + .insert(leased_key, Bytes::from(DATA).into()) + .await; + MockClock::advance(Duration::from_secs(10)); + + let mut result = [None]; + evicting_map + .sizes_for_keys([&leased_key], &mut result, true) + .await; + assert_eq!( + result[0], + Some(DATA.len() as u64), + "TTL expiry must not remove a leased input", + ); + + evicting_map.release_key(&leased_key).await; + result[0] = None; + evicting_map + .sizes_for_keys([&leased_key], &mut result, true) + .await; + assert_eq!( + result[0], None, + "expired input may be reaped after its lease is released", + ); + + Ok(()) +} + #[nativelink_test] async fn insert_purges_to_low_watermark_at_max_bytes() -> Result<(), Error> { const DATA: &str = "12345678"; @@ -666,6 +1059,30 @@ async fn range_multiple_items_test() -> Result<(), Error> { Ok(()) } +#[nativelink_test] +async fn replacing_entry_keeps_filter_index_consistent() -> Result<(), Error> { + let evicting_map = EvictingMap::::new( + &EvictionPolicy::default(), + MockInstantWrapped::default(), + ); + let key = DigestInfo::try_new(HASH1, 0)?; + let first_value = BytesWrapper(Bytes::from_static(b"first")); + let second_value = BytesWrapper(Bytes::from_static(b"second")); + + evicting_map.enable_filtering().await; + evicting_map.insert(key, first_value).await; + evicting_map.insert(key, second_value.clone()).await; + + let mut values = Vec::new(); + evicting_map.range(.., |_, value| { + values.push(value.clone()); + true + }); + assert_eq!(values, vec![second_value]); + + Ok(()) +} + // `LenEntry` impl that records every `unref()` invocation so tests can // observe whether reads or writes call into eviction paths. #[derive(Clone, Debug)] diff --git a/nativelink-util/tests/metrics_test.rs b/nativelink-util/tests/metrics_test.rs index d4e83f1a6..3a073884e 100644 --- a/nativelink-util/tests/metrics_test.rs +++ b/nativelink-util/tests/metrics_test.rs @@ -12,10 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -use nativelink_util::action_messages::{ActionResult, ActionStage}; +use nativelink_util::action_messages::{ + ActionResult, ActionStage, ExecutionMetadata, FileInfo, NameOrPath, +}; +use nativelink_util::common::DigestInfo; use nativelink_util::metrics::{ CACHE_METRICS, CacheMetricAttrs, EXECUTION_METRICS, ExecutionMetricAttrs, ExecutionStage, - make_execution_attributes, + WORKER_METRICS, WorkerDisconnectReason, execution_output_bytes, make_execution_attributes, + peak_memory_sample, pool_available_sample, record_completed_execution_metrics, + record_connection_acquired, record_connection_reconnect, record_execution_cpu_time, + record_execution_peak_memory, record_health_check, record_matching_pass, record_rpc_served, + record_store_tier_io, record_store_tier_read, record_worker_connected, + record_worker_disconnected, record_worker_keepalive, record_worker_state, split_grpc_path, }; use opentelemetry::KeyValue; @@ -110,6 +118,7 @@ fn test_metrics_lazy_initialization() { // Verify that the lazy static initialization works let _cache_metrics = &*CACHE_METRICS; let _execution_metrics = &*EXECUTION_METRICS; + let _worker_metrics = &*WORKER_METRICS; // If we got here without panicking, the metrics were initialized successfully } @@ -195,3 +204,187 @@ fn test_action_stage_conversion_avoids_clone() { "Reference conversion took too long: {elapsed:?}" ); } + +#[test] +fn execution_output_bytes_sums_files_and_streams() { + let hash = "0123456789abcdef000000000000000000010000000000000123456789abcdef"; + let result = ActionResult { + output_files: vec![ + FileInfo { + name_or_path: NameOrPath::Path("out1".to_string()), + digest: DigestInfo::try_new(hash, 1000).unwrap(), + is_executable: false, + }, + FileInfo { + name_or_path: NameOrPath::Path("out2".to_string()), + digest: DigestInfo::try_new(hash, 234).unwrap(), + is_executable: false, + }, + ], + stdout_digest: DigestInfo::try_new(hash, 10).unwrap(), + stderr_digest: DigestInfo::try_new(hash, 20).unwrap(), + ..ActionResult::default() + }; + assert_eq!(execution_output_bytes(&result), 1000 + 234 + 10 + 20); +} + +#[test] +fn record_completed_execution_metrics_guards_unpopulated_metadata() { + use core::time::Duration; + use std::time::SystemTime; + + let queued = SystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000); + let at = |n| queued + Duration::from_secs(n); + let populated = ActionResult { + execution_metadata: ExecutionMetadata { + queued_timestamp: queued, + worker_start_timestamp: at(2), + worker_completed_timestamp: at(12), + input_fetch_start_timestamp: at(2), + input_fetch_completed_timestamp: at(4), + execution_start_timestamp: at(4), + execution_completed_timestamp: at(11), + output_upload_start_timestamp: at(11), + output_upload_completed_timestamp: at(12), + ..ExecutionMetadata::default() + }, + ..ActionResult::default() + }; + // Should record without panicking. + record_completed_execution_metrics(&populated, "instance", Some("worker-1"), Some(3)); + + // Default (UNIX_EPOCH) metadata must skip the duration records cleanly. + record_completed_execution_metrics(&ActionResult::default(), "instance", None, None); +} + +#[test] +fn test_worker_disconnect_reason_labels() { + // These become metric label values, so they are part of the wire contract + // and dashboards break if they change. + assert_eq!( + WorkerDisconnectReason::Disconnected.as_str(), + "disconnected" + ); + assert_eq!(WorkerDisconnectReason::Evicted.as_str(), "evicted"); +} + +#[test] +fn test_worker_metric_helpers_are_callable() { + // The instruments are global, so there is nothing to read back here + // without a test exporter. This guards the call sites: every helper stays + // callable with the arguments the scheduler passes. + record_worker_connected(); + record_worker_keepalive(); + record_worker_state("draining", true); + record_worker_state("draining", false); + record_worker_disconnected(WorkerDisconnectReason::Disconnected, false, false); + + // A worker that was draining and paused when it left unwinds both gauges. + record_worker_connected(); + record_worker_state("draining", true); + record_worker_state("paused", true); + record_worker_disconnected(WorkerDisconnectReason::Evicted, true, true); +} + +#[test] +fn test_split_grpc_path() { + assert_eq!( + split_grpc_path( + "/build.bazel.remote.execution.v2.ContentAddressableStorage/FindMissingBlobs" + ), + ( + "build.bazel.remote.execution.v2.ContentAddressableStorage", + "FindMissingBlobs" + ) + ); + assert_eq!( + split_grpc_path("/google.bytestream.ByteStream/Write"), + ("google.bytestream.ByteStream", "Write") + ); + // Not a gRPC route. Reported whole rather than dropped, so an unexpected + // path is still visible. + assert_eq!(split_grpc_path("/healthz"), ("healthz", "unknown")); + assert_eq!(split_grpc_path(""), ("", "unknown")); +} + +#[test] +fn test_health_status_metric_labels() { + use std::borrow::Cow; + + use nativelink_util::health_utils::HealthStatus; + + // Label values are part of the wire contract for dashboards. + assert_eq!( + HealthStatus::Ok { + struct_name: "S", + message: Cow::Borrowed("") + } + .metric_label(), + "ok" + ); + assert_eq!( + HealthStatus::Failed { + struct_name: "S", + message: Cow::Borrowed("") + } + .metric_label(), + "failed" + ); + assert_eq!( + HealthStatus::Timeout { struct_name: "S" }.metric_label(), + "timeout" + ); +} + +#[test] +fn test_new_metric_helpers_are_callable() { + // Global instruments, so nothing to read back without a test exporter. + // This guards the call sites against drift. + record_rpc_served("/pkg.Service/Method", 0, 0.01); + record_rpc_served("/pkg.Service/Method", 5, 1.5); + record_matching_pass(0.002, true); + record_matching_pass(0.002, false); + record_store_tier_read("fast", "hit"); + record_store_tier_read("slow", "hit"); + record_store_tier_io("fast", "read", 4096); + record_health_check("store", "ok"); + record_execution_peak_memory(512 * 1024, "main"); + record_execution_cpu_time(90_000, "main"); + record_connection_acquired("grpc", Some(12), false); + record_connection_acquired("redis", Some(0), true); + record_connection_acquired("grpc", None, false); + record_connection_reconnect("redis"); +} + +/// An unlimited pool is a semaphore holding `Semaphore::MAX_PERMITS`, about +/// 2.3e18. Recording that as a histogram sample overflowed the SDK's `u64` +/// sum within a handful of samples and panicked a debug build, which killed a +/// tokio worker and turned every later connection request into a `SendError`. +/// +/// Callers now pass `None` for an unlimited pool. This covers the clamp that +/// backstops them, which is the part that can be asserted without installing +/// a meter provider. +#[test] +fn pool_available_sample_clamps_an_unbounded_permit_count() { + // Semaphore::MAX_PERMITS. + assert_eq!(pool_available_sample(usize::MAX >> 3), 1024); + assert_eq!(pool_available_sample(usize::MAX), 1024); + // Real counts pass through untouched. + assert_eq!(pool_available_sample(0), 0); + assert_eq!(pool_available_sample(12), 12); + assert_eq!(pool_available_sample(1024), 1024); +} + +/// Peak memory arrives from a worker over gRPC, so a malfunctioning one could +/// report a value that overflows the histogram's `u64` sum the same way an +/// unbounded connection pool did. +#[test] +fn peak_memory_sample_bounds_an_absurd_reading() { + // KiB to bytes for anything plausible. + assert_eq!(peak_memory_sample(0), 0); + assert_eq!(peak_memory_sample(1), 1024); + assert_eq!(peak_memory_sample(4 * 1024 * 1024), 4 * 1024 * 1024 * 1024); + // Absurd readings are bounded rather than wrapped. + assert_eq!(peak_memory_sample(u64::MAX), 1 << 50); + assert_eq!(peak_memory_sample(u64::MAX / 512), 1 << 50); +} diff --git a/nativelink-util/tests/origin_event_test.rs b/nativelink-util/tests/origin_event_test.rs index 5404ad278..9f72e7d05 100644 --- a/nativelink-util/tests/origin_event_test.rs +++ b/nativelink-util/tests/origin_event_test.rs @@ -29,9 +29,7 @@ use nativelink_util::default_health_status_indicator; use nativelink_util::health_utils::HealthStatusIndicator; use nativelink_util::origin_event::get_id_for_event; use nativelink_util::origin_event_publisher::OriginEventPublisher; -use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, UploadSizeInfo, -}; +use nativelink_util::store_trait::{RemoveCallback, Store, StoreDriver, StoreKey, UploadSizeInfo}; use tokio::sync::{broadcast, mpsc}; use tokio::time::sleep; use tonic::async_trait; @@ -100,10 +98,7 @@ impl StoreDriver for FlakyStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { todo!(); } } diff --git a/nativelink-util/tests/store_trait_test.rs b/nativelink-util/tests/store_trait_test.rs index c09b03838..0cecc7ee3 100644 --- a/nativelink-util/tests/store_trait_test.rs +++ b/nativelink-util/tests/store_trait_test.rs @@ -8,7 +8,7 @@ use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::default_health_status_indicator; use nativelink_util::health_utils::HealthStatusIndicator; use nativelink_util::store_trait::{ - RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, + RemoveCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, }; use tonic::async_trait; @@ -61,10 +61,7 @@ impl StoreDriver for FakeStore { self } - fn register_remove_callback( - self: Arc, - _callback: Arc, - ) -> Result<(), Error> { + fn register_remove_callback(self: Arc, _callback: RemoveCallback) -> Result<(), Error> { todo!(); } } diff --git a/nativelink-util/tests/telemetry_test.rs b/nativelink-util/tests/telemetry_test.rs index 56d19f1bb..956f34849 100644 --- a/nativelink-util/tests/telemetry_test.rs +++ b/nativelink-util/tests/telemetry_test.rs @@ -238,7 +238,7 @@ impl Service> for TestMetricsService { ); // ProstCodec: Encode = T (sent to client), // Decode = U (received from client). - let mut grpc = tonic::server::Grpc::new(tonic::codec::ProstCodec::< + let mut grpc = tonic::server::Grpc::new(tonic_prost::ProstCodec::< ExportMetricsServiceResponse, ExportMetricsServiceRequest, >::default()); @@ -385,6 +385,7 @@ fn expected_sum_data_points() -> Vec<(String, String, Vec, String)> { value: Some(AnyValue { value: Some(any_value::Value::StringValue(value.to_string())), }), + key_strindex: 0, } ) }; diff --git a/nativelink-util/tests/wire_compression_test.rs b/nativelink-util/tests/wire_compression_test.rs new file mode 100644 index 000000000..935bb2119 --- /dev/null +++ b/nativelink-util/tests/wire_compression_test.rs @@ -0,0 +1,132 @@ +// Copyright 2026 The NativeLink Authors. All rights reserved. +// +// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// See LICENSE file for details +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use bytes::Bytes; +use nativelink_error::Error; +use nativelink_macro::nativelink_test; +use nativelink_proto::build::bazel::remote::execution::v2::compressor; +use nativelink_util::buf_channel::make_buf_channel_pair; +use nativelink_util::common::DigestInfo; +use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc}; +use nativelink_util::wire_compression::{ + ZSTD_COMPRESSION_LEVEL, stream_decode_compressed_upload, stream_encode_compressed_download, +}; +use pretty_assertions::assert_eq; + +fn make_content_with_digest(tag: u8, len: usize) -> (Bytes, DigestInfo) { + let mut data = vec![0u8; len]; + for (i, b) in data.iter_mut().enumerate() { + #[allow(clippy::cast_possible_truncation)] + let byte = match i % 8 { + 0..=4 => tag, + 5 => (i / 8) as u8, + _ => (i / 4096) as u8, + }; + *b = byte; + } + let mut hasher = DigestHasherFunc::Sha256.hasher(); + hasher.update(&data); + let digest = hasher.finalize_digest(); + (Bytes::from(data), digest) +} + +async fn decode_chunks( + frame: Bytes, + split_at: usize, + digest: DigestInfo, +) -> (Result<(), Error>, Result) { + let (mut compressed_tx, compressed_rx) = make_buf_channel_pair(); + let (decoded_tx, mut decoded_rx) = make_buf_channel_pair(); + let decode_fut = stream_decode_compressed_upload( + compressed_rx, + compressor::Value::Zstd, + digest, + DigestHasherFunc::Sha256, + decoded_tx, + ); + let feed_fut = async move { + compressed_tx.send(frame.slice(0..split_at)).await?; + if split_at < frame.len() { + compressed_tx.send(frame.slice(split_at..)).await?; + } + compressed_tx.send_eof() + }; + let pump_fut = async move { + let mut total = 0usize; + loop { + let chunk = decoded_rx.recv().await?; + if chunk.is_empty() { + return Ok(total); + } + total += chunk.len(); + } + }; + let (feed_result, decode_result, pump_result) = tokio::join!(feed_fut, decode_fut, pump_fut); + feed_result.expect("feed must succeed"); + (decode_result, pump_result) +} + +// Regression: a blob whose decompressed size is an exact multiple of the +// decoder output buffer (128KiB) made the final `run` fill the output +// exactly with `hint == 0` (frame done); the loop then polled the finished +// decoder once more, received the new-frame-header hint, and the EOF check +// misreported the complete stream as truncated. +#[nativelink_test] +async fn decode_accepts_exact_output_buffer_multiple() -> Result<(), Error> { + let (content, digest) = make_content_with_digest(0xB2, 1024 * 1024); + let frame = + Bytes::from(zstd::bulk::compress(&content, ZSTD_COMPRESSION_LEVEL).expect("compress")); + let (decode_result, pump_result) = decode_chunks(frame, 65536, digest).await; + decode_result.expect("exact-multiple frame must decode"); + assert_eq!(pump_result.expect("pump"), content.len()); + Ok(()) +} + +// Encode -> decode round trip through the streaming codecs. +#[nativelink_test] +async fn stream_encode_decode_round_trip() -> Result<(), Error> { + let (content, digest) = make_content_with_digest(0xC4, 300_000); + let (mut raw_tx, raw_rx) = make_buf_channel_pair(); + let (compressed_tx, mut compressed_rx) = make_buf_channel_pair(); + let encode_fut = stream_encode_compressed_download( + raw_rx, + compressor::Value::Zstd, + ZSTD_COMPRESSION_LEVEL, + compressed_tx, + ); + let content_for_send = content.clone(); + let send_fut = async move { + raw_tx.send(content_for_send).await?; + raw_tx.send_eof() + }; + let collect_fut = async move { + let mut frame = Vec::new(); + loop { + let chunk = compressed_rx.recv().await?; + if chunk.is_empty() { + return Ok::<_, Error>(Bytes::from(frame)); + } + frame.extend_from_slice(&chunk); + } + }; + let (send_result, encode_result, frame) = tokio::join!(send_fut, encode_fut, collect_fut); + send_result.expect("send"); + encode_result.expect("encode"); + let frame = frame.expect("collect"); + + let (decode_result, pump_result) = decode_chunks(frame, 1, digest).await; + decode_result.expect("decode"); + assert_eq!(pump_result.expect("pump"), content.len()); + Ok(()) +} diff --git a/nativelink-worker/BUILD.bazel b/nativelink-worker/BUILD.bazel index 1dbad5e5c..899b84cf4 100644 --- a/nativelink-worker/BUILD.bazel +++ b/nativelink-worker/BUILD.bazel @@ -66,6 +66,7 @@ rust_test_suite( name = "integration", timeout = "short", srcs = [ + "tests/directory_cache_stress_test.rs", "tests/directory_cache_test.rs", "tests/local_worker_test.rs", "tests/namespace_utils_test.rs", @@ -84,6 +85,7 @@ rust_test_suite( ":nativelink-worker", "//nativelink-config", "//nativelink-error", + "//nativelink-metric", "//nativelink-proto", "//nativelink-store", "//nativelink-util", @@ -99,6 +101,7 @@ rust_test_suite( "@crates//:serial_test", "@crates//:tokio", "@crates//:tonic", + "@crates//:tonic-prost", "@crates//:tracing", "@crates//:tracing-test", "@crates//:uuid", diff --git a/nativelink-worker/Cargo.toml b/nativelink-worker/Cargo.toml index e6aebabe0..528bb8a1c 100644 --- a/nativelink-worker/Cargo.toml +++ b/nativelink-worker/Cargo.toml @@ -4,7 +4,7 @@ lints.workspace = true [package] edition = "2024" name = "nativelink-worker" -version = "1.5.2" +version = "1.6.4" [features] nix = [] @@ -23,9 +23,9 @@ dunce = { version = "1.0.5", default-features = false } filetime = { version = "0.2.25", default-features = false } formatx = { version = "0.2.3", default-features = false } futures = { version = "0.3.31", default-features = false } -opentelemetry = { version = "0.30.0", default-features = false } +opentelemetry = { version = "0.32.0", default-features = false } parking_lot = { version = "0.12.3", default-features = false } -prost = { version = "0.13.5", default-features = false } +prost = { version = "0.14.4", default-features = false } relative-path = { version = "2.0.0", default-features = false, features = [ "alloc", "std", @@ -47,7 +47,7 @@ tokio = { version = "1.52.2", features = [ tokio-stream = { version = "0.1.17", default-features = false, features = [ "fs", ] } -tonic = { version = "0.13.0", features = [ +tonic = { version = "0.14.0", features = [ "gzip", "tls-ring", "transport", @@ -67,16 +67,18 @@ libc = { version = "0.2.183", default-features = false } [dev-dependencies] nativelink-macro = { path = "../nativelink-macro" } +async-trait = { version = "0.1.88", default-features = false } hyper = { version = "1.6.0", default-features = false } pathdiff = { version = "0.2.3", default-features = false } pretty_assertions = { version = "1.4.1", features = [ "std", ], default-features = false } -prost-types = { version = "0.13.5", default-features = false } +prost-types = { version = "0.14.4", default-features = false } serial_test = { version = "3.2.0", features = [ "async", ], default-features = false } tempfile = { version = "3.15.0", default-features = false } +tonic-prost = { version = "0.14.6", default-features = false } tracing-test = { version = "0.2.5", default-features = false, features = [ "no-env-filter", ] } diff --git a/nativelink-worker/src/directory_cache.rs b/nativelink-worker/src/directory_cache.rs index db91e2991..259e74810 100644 --- a/nativelink-worker/src/directory_cache.rs +++ b/nativelink-worker/src/directory_cache.rs @@ -14,27 +14,68 @@ use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{AtomicU64, Ordering}; +use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::sync::Arc; -use std::time::SystemTime; +use std::time::{SystemTime, UNIX_EPOCH}; +use futures::StreamExt; +use futures::future::BoxFuture; +use futures::stream::TryStreamExt; use nativelink_error::{Code, Error, ResultExt, make_err}; +use nativelink_metric::{ + MetricFieldData, MetricKind, MetricPublishKnownKindData, MetricsComponent, group, publish, +}; use nativelink_proto::build::bazel::remote::execution::v2::{ - Directory as ProtoDirectory, DirectoryNode, FileNode, SymlinkNode, + Directory as ProtoDirectory, DirectoryNode, FileNode, GetTreeRequest, SymlinkNode, }; use nativelink_store::ac_utils::get_and_decode_digest; use nativelink_store::cas_utils::is_zero_digest; use nativelink_store::fast_slow_store::FastSlowStore; use nativelink_store::filesystem_store::{FileEntry, FilesystemStore}; +use nativelink_store::grpc_store::GrpcStore; use nativelink_util::background_spawn; use nativelink_util::common::DigestInfo; +use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc, default_digest_hasher_func}; use nativelink_util::fs_util::{CloneMethod, hardlink_directory_tree, set_dir_writable_recursive}; use nativelink_util::store_trait::{StoreKey, StoreLike}; +use prost::Message; use tokio::fs; -use tokio::sync::{Mutex, RwLock}; -use tracing::{debug, trace, warn}; + +/// Maximum number of concurrently-polled node materializations (file +/// fetches, subdirectory recursions, symlink creations) per directory +/// level. Matches `DOWNLOAD_TO_DIRECTORY_CONCURRENCY` in +/// `running_actions_manager.rs`: enough parallelism to overlap slow-store +/// round trips, bounded so hardlink/copy syscalls do not fight the +/// filesystem's metadata locks (see the gate comment in +/// `download_to_directory`). +const CONSTRUCT_DIRECTORY_CONCURRENCY: usize = 64; + +/// Default for `DirectoryCacheConfig::max_concurrent_fetches`, preserving +/// the historical cache-wide fetch bound. +const DEFAULT_MAX_CONCURRENT_FETCHES: usize = 64; +use tokio::sync::{Mutex, RwLock, Semaphore}; +use tracing::{debug, info, trace, warn}; + +/// Prefix for in-progress construction trees under `cache_root`. Cache-entry +/// names are digest strings (hex), so dot-prefixed scratch names can never +/// collide with a published entry. +const TEMP_PREFIX: &str = ".tmp-"; + +/// Prefix for eviction tombstones awaiting background deletion. +const TOMBSTONE_PREFIX: &str = ".del-"; + +/// Minimum interval between summary log lines, in nanoseconds (one minute). +const SUMMARY_LOG_INTERVAL_NANOS: u64 = 60_000_000_000; + +/// Current time as nanoseconds since the unix epoch, for lock-free LRU +/// timestamps. Saturates instead of failing (`u64` nanos overflow in 2554). +fn unix_nanos_now() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map_or(0, |d| u64::try_from(d.as_nanos()).unwrap_or(u64::MAX)) +} /// Configuration for the directory cache #[derive(Debug, Clone)] @@ -45,6 +86,39 @@ pub struct DirectoryCacheConfig { pub max_size_bytes: u64, /// Base directory for cache storage pub cache_root: PathBuf, + /// Experimental: additionally cache every subdirectory by its own + /// `Directory` digest so unchanged subtrees are shared across different + /// root digests. Subtree entries participate in normal eviction and + /// multiply the entry count, so `max_entries` should be raised when + /// enabling this. Default: false (root-only caching, existing behavior). + pub experimental_subtree_caching: bool, + /// Maximum number of concurrent slow-store fetches across ALL directory + /// constructions of this cache. Permits are held only across leaf I/O + /// (directory-proto fetches, blob fetches/populates) and never across + /// subdirectory recursion, so recursion depth cannot deadlock the + /// semaphore. This is the bound that protects backing stores from RPC + /// storms: per-level construction concurrency compounds multiplicatively + /// across tree levels and concurrent actions (measured >1800 in-flight + /// fetches for 6 concurrent ~500-file trees without this cap). Low + /// values fragment coalesced/batched reads to at most this many items; + /// see the config-crate doc for the `experimental_read_batching` + /// interaction. Must be > 0. Default: 64. + pub max_concurrent_fetches: usize, + /// See `nativelink-config`'s `DirectoryCacheConfig::experimental_get_tree_prefetch`. + pub experimental_get_tree_prefetch: bool, +} + +/// Receives every CAS digest before the directory cache starts materializing +/// that node. Action workers use this hook to keep the digest pinned in their +/// local eviction-managed CAS tiers for the duration of the action. +pub trait DigestLease: Send + Sync { + fn acquire(&self, digest: &DigestInfo); +} + +fn acquire_digest(lease: Option<&dyn DigestLease>, digest: &DigestInfo) { + if let Some(lease) = lease { + lease.acquire(digest); + } } impl Default for DirectoryCacheConfig { @@ -53,21 +127,77 @@ impl Default for DirectoryCacheConfig { max_entries: 1000, max_size_bytes: 10 * 1024 * 1024 * 1024, // 10 GB cache_root: std::env::temp_dir().join("nativelink_directory_cache"), + experimental_subtree_caching: false, + max_concurrent_fetches: DEFAULT_MAX_CONCURRENT_FETCHES, + experimental_get_tree_prefetch: false, } } } /// Metadata for a cached directory -#[derive(Debug, Clone)] +#[derive(Debug)] struct CachedDirectoryMetadata { /// Path to the cached directory path: PathBuf, - /// Size in bytes + /// Recorded size in bytes. With subtree caching enabled this covers only + /// bytes not owned by a descendant entry, so the sum over the map + /// approximates unique materialized bytes. size: u64, - /// Last access time for LRU eviction - last_access: SystemTime, - /// Reference count (number of active users) - ref_count: usize, + /// Last access time (nanoseconds since the unix epoch) for LRU eviction. + /// Atomic so cache hits can refresh it under the cache READ lock instead + /// of serializing on the write lock. + last_access: AtomicU64, + /// Number of active users. Shared with the [`EntryPin`] RAII guards + /// handed out by `acquire_entry`, which decrement it on drop — even when + /// the future holding the pin is cancelled mid-await. Eviction skips + /// entries with a non-zero count. + ref_count: Arc, +} + +/// RAII pin on a cache entry: while alive, eviction will not select the +/// entry, so its on-disk tree cannot be deleted out from under an unlocked +/// materialization. Dropping the pin releases it — including implicitly when +/// a construction future is cancelled (e.g. `buffer_unordered` dropping +/// sibling futures after another node errors), so pins can never leak and +/// permanently block eviction. +#[derive(Debug)] +struct EntryPin { + ref_count: Arc, +} + +impl Drop for EntryPin { + fn drop(&mut self) { + self.ref_count.fetch_sub(1, Ordering::SeqCst); + } +} + +/// Drop guard for an in-progress temp construction tree: if the owning +/// future is dropped before [`Self::disarm`] (cancellation — e.g. +/// `buffer_unordered` drops sibling constructions on the first error), the +/// partial tree is deleted in the background. Error paths instead disarm and +/// clean up inline so a failed construction leaves nothing behind by the +/// time the error propagates. +#[derive(Debug)] +struct ScratchGuard { + path: Option, +} + +impl ScratchGuard { + const fn new(path: PathBuf) -> Self { + Self { path: Some(path) } + } + + fn disarm(&mut self) { + self.path = None; + } +} + +impl Drop for ScratchGuard { + fn drop(&mut self) { + if let Some(path) = self.path.take() { + DirectoryCache::dispatch_evictions(vec![path]); + } + } } /// High-performance directory cache that uses hardlinks to avoid repeated @@ -95,11 +225,39 @@ pub struct DirectoryCache { /// (zero-copy) instead of fetched into RAM and rewritten. When absent /// (e.g. an unusual store layout) the cache falls back to fetch+write. filesystem_store: Option>, + /// Global slow-fetch budget shared by all constructions of this cache; + /// see `DirectoryCacheConfig::max_concurrent_fetches`. + fetch_permits: Semaphore, /// Count of materializations that used APFS `clonefile(2)` (macOS only; /// always zero on other platforms). clonefile_hits: AtomicU64, /// Count of materializations that used per-file `fs::hard_link`. hardlink_hits: AtomicU64, + /// Count of subtree materializations served from the cache by the + /// subtree's own `Directory` digest. Only ever non-zero when + /// `experimental_subtree_caching` is enabled. + subtree_hits: AtomicU64, + /// Count of subtree constructions that could not be served from the + /// cache. Only ever non-zero when `experimental_subtree_caching` is + /// enabled. + subtree_misses: AtomicU64, + /// Count of entries removed by LRU eviction. A high rate relative to + /// hits means the cache is thrashing (`max_entries`/`max_size_bytes` too + /// small for the workload — especially with subtree caching enabled, + /// which multiplies the entry count). + evictions: AtomicU64, + /// Monotonic counter for process-unique scratch names (temp construction + /// trees and eviction tombstones) under `cache_root`. + scratch_seq: AtomicU64, + /// Mirror of the map's entry count, maintained at insert/evict/invalidate + /// so the sync `MetricsComponent::publish` and the rate-limited log + /// summary can read it without touching the async `RwLock`. + map_entries: AtomicU64, + /// Mirror of the map's total recorded size in bytes (see `map_entries`). + map_size_bytes: AtomicU64, + /// Timestamp (unix nanos) of the last summary log line, for rate + /// limiting. + last_summary_log: AtomicU64, } impl DirectoryCache { @@ -112,6 +270,15 @@ impl DirectoryCache { config: DirectoryCacheConfig, cas_store: Arc, ) -> Result { + // A zero-permit semaphore would deadlock every construction. + if config.max_concurrent_fetches == 0 { + return Err(make_err!( + Code::InvalidArgument, + "directory_cache max_concurrent_fetches must be greater than 0" + )); + } + let max_concurrent_fetches = config.max_concurrent_fetches; + // Ensure cache root exists fs::create_dir_all(&config.cache_root).await.err_tip(|| { format!( @@ -134,15 +301,101 @@ impl DirectoryCache { ); } - Ok(Self { + let cache = Self { config, cache: Arc::new(RwLock::new(HashMap::new())), construction_locks: Arc::new(Mutex::new(HashMap::new())), cas_store, filesystem_store, + fetch_permits: Semaphore::new(max_concurrent_fetches), clonefile_hits: AtomicU64::new(0), hardlink_hits: AtomicU64::new(0), - }) + subtree_hits: AtomicU64::new(0), + subtree_misses: AtomicU64::new(0), + evictions: AtomicU64::new(0), + scratch_seq: AtomicU64::new(0), + map_entries: AtomicU64::new(0), + map_size_bytes: AtomicU64::new(0), + last_summary_log: AtomicU64::new(0), + }; + cache.sweep_cache_root().await; + Ok(cache) + } + + /// Sweeps pre-existing content of `cache_root`. The in-memory map starts + /// empty, so anything already on disk is orphaned: entries from a + /// previous process (unusable — they are not in the map, and a partial + /// one would poison re-construction of its digest), plus stale temp + /// trees and tombstones. Each orphan is renamed to a tombstone + /// synchronously — after `new` returns, a fresh construction could + /// otherwise publish to the very canonical path a detached deletion is + /// about to remove — and the tombstones are deleted in the background. + async fn sweep_cache_root(&self) { + let mut orphans = Vec::new(); + match fs::read_dir(&self.config.cache_root).await { + Ok(mut dir) => loop { + match dir.next_entry().await { + Ok(Some(entry)) => orphans.push(entry.path()), + Ok(None) => break, + Err(e) => { + warn!(error = ?e, "Failed reading cache root during orphan sweep"); + break; + } + } + }, + Err(e) => { + warn!(error = ?e, "Failed to scan cache root for orphaned entries"); + return; + } + } + if orphans.is_empty() { + return; + } + debug!( + count = orphans.len(), + "Sweeping orphaned directory cache content" + ); + let tombstones = self.tombstone_victims(orphans).await; + Self::dispatch_evictions(tombstones); + } + + /// Acquires a permit from the cache-wide slow-fetch budget. Held only + /// across leaf I/O awaits, never across subdirectory recursion. + async fn acquire_fetch_permit(&self) -> Result, Error> { + self.fetch_permits + .acquire() + .await + .map_err(|e| make_err!(Code::Internal, "Fetch semaphore closed: {e:?}")) + } + + /// Emits an `info!` summary of the cache counters, rate-limited to at + /// most one line per [`SUMMARY_LOG_INTERVAL_NANOS`]. Called from the + /// hit/miss path so deployments without a metrics pipeline can still + /// verify the cache is working by grepping worker logs. + fn maybe_log_summary(&self) { + let now = unix_nanos_now(); + let last = self.last_summary_log.load(Ordering::Relaxed); + if now.saturating_sub(last) < SUMMARY_LOG_INTERVAL_NANOS { + return; + } + // Single winner per interval; losers skip the log line. + if self + .last_summary_log + .compare_exchange(last, now, Ordering::Relaxed, Ordering::Relaxed) + .is_err() + { + return; + } + info!( + clonefile_hits = self.clonefile_hits.load(Ordering::Relaxed), + hardlink_hits = self.hardlink_hits.load(Ordering::Relaxed), + subtree_hits = self.subtree_hits.load(Ordering::Relaxed), + subtree_misses = self.subtree_misses.load(Ordering::Relaxed), + evictions = self.evictions.load(Ordering::Relaxed), + entries = self.map_entries.load(Ordering::Relaxed), + total_size_bytes = self.map_size_bytes.load(Ordering::Relaxed), + "DirectoryCache summary" + ); } /// Records which kernel mechanism materialized a tree, for observability. @@ -165,33 +418,56 @@ impl DirectoryCache { /// * `Ok(false)` - Cache miss (directory was constructed) /// * `Err` - Error during construction or hardlinking pub async fn get_or_create(&self, digest: DigestInfo, dest_path: &Path) -> Result { - // Fast path: check if already in cache. - // - // The cache write lock is held only long enough to bump `ref_count` - // and snapshot the entry's path — NOT across the syscall-heavy - // `hardlink_directory_tree`. A global lock held across that - // materialization serializes every concurrent `get_or_create`. The - // `ref_count` bump is what makes releasing the lock safe: eviction - // skips any entry with `ref_count > 0`, so the cache path cannot be - // deleted out from under the unlocked materialization. - if let Some(cache_path) = self.acquire_entry(&digest).await { - debug!(?digest, ?cache_path, "Directory cache HIT"); - let result = hardlink_directory_tree(&cache_path, dest_path).await; - self.release_entry(&digest).await; - match result { - Ok(method) => { - self.record_clone_method(method); - return Ok(true); - } - Err(e) => { - warn!( - ?digest, - error = ?e, - "Failed to hardlink from cache, will reconstruct" - ); - // Fall through to reconstruction. - } - } + self.get_or_create_with_lease(digest, dest_path, None).await + } + + /// Gets or creates a cached directory while optionally reserving each CAS + /// digest used by a construction. + /// + /// Existing cache hits only hardlink from the already-materialized cache + /// entry, whose own pin protects the source tree. On a miss, the lease is + /// called before the root, file, and child-directory digests are fetched + /// or populated, closing the admission-to-eviction race for active + /// actions. + pub async fn get_or_create_with_lease( + &self, + digest: DigestInfo, + dest_path: &Path, + lease: Option<&dyn DigestLease>, + ) -> Result { + let (hit, _size) = self + .get_or_create_entry(digest, dest_path, None, true, lease) + .await?; + Ok(hit) + } + + /// Core get-or-create flow shared by root materializations + /// ([`Self::get_or_create`]) and, with `experimental_subtree_caching` + /// enabled, subtree materializations (`create_subdirectory`). Returns + /// `(hit, size)` where `hit` is true when the destination was served by + /// hardlinking an existing cache entry, and `size` is the entry's + /// recorded size in bytes. + /// + /// `protos` is a map of prefetched `Directory` protos consulted during + /// construction (see [`Self::prefetch_tree_protos`]); `prefetch_on_miss` + /// is true only for root-level calls, which issue the tree's logical + /// `GetTree` prefetch on a cold miss. Subtree flights pass the root's + /// map down instead, so cache hits (root or subtree) never prefetch. A + /// server may paginate that traversal across multiple RPCs. + async fn get_or_create_entry( + &self, + digest: DigestInfo, + dest_path: &Path, + protos: Option<&HashMap>, + prefetch_on_miss: bool, + lease: Option<&dyn DigestLease>, + ) -> Result<(bool, u64), Error> { + self.maybe_log_summary(); + acquire_digest(lease, &digest); + + // Fast path: serve from an existing entry. + if let Some(size) = self.try_materialize_from_cache(&digest, dest_path).await { + return Ok((true, size)); } debug!(?digest, "Directory cache MISS"); @@ -200,7 +476,11 @@ impl DirectoryCache { // Concurrent callers for the same digest block on this per-digest // mutex; when the constructor finishes and inserts the entry, the // waiters wake, find it in the cache, and materialize their own - // destination from the single shared cache entry. + // destination from the single shared cache entry. Root and subtree + // flights for the same digest share one mutex, and the lock order is + // deadlock-free by construction: a flight only ever waits on locks + // of its strict descendants, and the content-addressed Merkle DAG is + // acyclic. let construction_lock = { let mut locks = self.construction_locks.lock().await; locks @@ -215,47 +495,92 @@ impl DirectoryCache { // outcome so it cannot grow unbounded. The guard (`_guard`) is still // held until the end of this function — `forget_construction_lock` // only unmaps the Arc; any waiter already cloned it before blocking. - let result = self.construct_and_materialize(digest, dest_path).await; + let result = self + .construct_and_materialize(digest, dest_path, protos, prefetch_on_miss, lease) + .await; self.forget_construction_lock(&digest).await; result } + /// Attempts to serve `digest` from an existing cache entry by hardlinking + /// it to `dest_path`, returning the entry's recorded size on success. + /// + /// The entry is pinned (see [`EntryPin`]) across the unlocked + /// `hardlink_directory_tree` so eviction cannot delete its tree + /// mid-materialization; only the brief refcount/LRU bookkeeping runs + /// under the cache lock (the READ lock — hits never serialize on the + /// write lock). + /// + /// Returns `None` when the digest is not cached, or when the entry's + /// on-disk tree failed to hardlink (missing/corrupt). In the failure + /// case the dead entry has been invalidated (removed + tombstoned, so it + /// cannot fail every future request forever) and the possibly partially + /// populated destination cleared, so the caller can construct fresh. + async fn try_materialize_from_cache( + &self, + digest: &DigestInfo, + dest_path: &Path, + ) -> Option { + let (cache_path, size, pin) = self.acquire_entry(digest).await?; + debug!(?digest, ?cache_path, "Directory cache HIT"); + match hardlink_directory_tree(&cache_path, dest_path).await { + Ok(method) => { + drop(pin); + self.record_clone_method(method); + Some(size) + } + Err(e) => { + warn!( + ?digest, + error = ?e, + "Failed to hardlink from cache, invalidating entry and reconstructing" + ); + self.invalidate_entry(digest, &pin).await; + drop(pin); + // The failed walk may have partially populated the + // destination; clear it so the reconstruction starts clean + // (`hardlink_directory_tree` refuses an existing destination + // and `create_file` fails on leftovers). + Self::remove_tree_best_effort(dest_path).await; + None + } + } + } + /// The cache-miss body, run while holding the per-digest construction - /// guard. Split out so `get_or_create` can unconditionally clean up the - /// construction-lock map entry afterwards on every exit path. + /// guard. Split out so `get_or_create_entry` can unconditionally clean up + /// the construction-lock map entry afterwards on every exit path. + /// `protos` and `prefetch_on_miss` are documented on + /// [`Self::get_or_create_entry`]. async fn construct_and_materialize( &self, digest: DigestInfo, dest_path: &Path, - ) -> Result { + protos: Option<&HashMap>, + prefetch_on_miss: bool, + lease: Option<&dyn DigestLease>, + ) -> Result<(bool, u64), Error> { // Re-check: another task may have just constructed this digest while - // we waited on the construction lock. - if let Some(cache_path) = self.acquire_entry(&digest).await { - let result = hardlink_directory_tree(&cache_path, dest_path).await; - self.release_entry(&digest).await; - match result { - Ok(method) => { - self.record_clone_method(method); - return Ok(true); - } - Err(e) => { - warn!( - ?digest, - error = ?e, - "Failed to hardlink after construction" - ); - // Construct directly at dest_path as a last resort. - self.construct_directory(digest, dest_path).await?; - return Ok(false); - } - } + // we waited on the construction lock. If the entry turns out to be + // damaged it is invalidated and we fall through to rebuild it fresh + // (exactly once — we hold the construction lock). + if let Some(size) = self.try_materialize_from_cache(&digest, dest_path).await { + return Ok((true, size)); } - // Construct the directory in cache. `construct_directory` returns the - // total tree size accumulated from `FileNode.digest.size_bytes` as it - // builds — no post-hoc filesystem walk is needed. It also sets every - // cache-entry directory's mode at creation time (0o755), so no - // separate permission-fixup walk is needed either. + // Construct the directory into a UNIQUE temp path first, then + // atomically publish it to the canonical `cache_root/` path + // via rename. Constructing at the canonical path directly would + // poison the digest on failure: the partial tree left behind makes + // every future construction of the digest fail on its leftovers — + // and subtree digests are stable across builds, so one poisoned + // popular subtree would fail every subsequent build. + // + // `construct_directory` returns the total tree size accumulated from + // `FileNode.digest.size_bytes` as it builds — no post-hoc filesystem + // walk is needed. It also sets every cache-entry directory's mode at + // creation time (0o755), so no separate permission-fixup walk is + // needed either. // // The cache entry's *files* are deliberately never chmod'd here: // non-executable files are hardlinks to FilesystemStore CAS blobs (see @@ -263,66 +588,200 @@ impl DirectoryCache { // with the CAS and every other in-flight action that hardlinked the // same blob — the inode-corruption bug PR #2347 fixed. let cache_path = self.get_cache_path(&digest); - let size = self.construct_directory(digest, &cache_path).await?; + // Root-level cold miss: prefetch the whole tree's `Directory` protos + // with one logical `GetTree` traversal, following server pagination. + // Subtree flights never prefetch — they inherit the root's map (or + // `None`) through `protos` instead. + let prefetched = if prefetch_on_miss { + Box::pin(self.prefetch_tree_protos(digest)).await + } else { + None + }; + let protos = prefetched.as_ref().or(protos); + let temp_path = self.allocate_scratch_path(TEMP_PREFIX); + let mut temp_guard = ScratchGuard::new(temp_path.clone()); + let size = match self + .construct_directory(digest, &temp_path, protos, lease) + .await + { + Ok(size) => size, + Err(e) => { + temp_guard.disarm(); + Self::remove_tree_best_effort(&temp_path).await; + return Err(e); + } + }; + + // Publish. A pre-existing canonical dir can only be crash leftovers + // from a previous process that the startup sweep has not yet + // removed: live entries are tracked in the map (this digest has no + // entry — we hold its construction lock and just re-checked), and + // eviction renames trees to tombstones under the cache write lock + // before deleting them. + Self::remove_tree_best_effort(&cache_path).await; + temp_guard.disarm(); + if let Err(e) = fs::rename(&temp_path, &cache_path).await { + Self::remove_tree_best_effort(&temp_path).await; + return Err(e) + .err_tip(|| format!("Failed to publish cache entry: {}", cache_path.display())); + } - // Insert into the cache. Only the in-memory map mutation runs under - // the write lock: `evict_if_needed` selects victims and removes them - // from the map here, but their filesystem deletion is dispatched off - // the lock so eviction I/O never serializes other callers. + // Insert into the cache. The in-memory map mutation and the + // metadata-cheap tombstone renames of evicted victims run under the + // write lock (see `tombstone_victims` for why the renames must); + // the expensive filesystem deletion is dispatched off the lock so + // eviction I/O never serializes other callers. // - // The new entry is inserted with `ref_count: 1` — pinned. The - // hardlink-to-destination below runs unlocked, and a concurrent - // `get_or_create` for an unrelated digest could otherwise pick this - // brand-new, last-accessed-now entry as an eviction victim and delete - // its tree mid-hardlink. The pin blocks that; `release_entry` drops it - // to 0 once the hardlink is done. - let evicted = { + // The new entry is inserted pre-pinned. The hardlink-to-destination + // below runs unlocked, and a concurrent caller for an unrelated + // digest could otherwise pick this brand-new entry as an eviction + // victim and delete its tree mid-hardlink. Dropping the pin releases + // it once the hardlink is done. + let ref_count = Arc::new(AtomicUsize::new(1)); + let pin = EntryPin { + ref_count: Arc::clone(&ref_count), + }; + let tombstones = { let mut cache = self.cache.write().await; - let evicted = self.evict_if_needed(size, &mut cache); - cache.insert( + let victims = self.evict_if_needed(size, &mut cache); + let replaced = cache.insert( digest, CachedDirectoryMetadata { path: cache_path.clone(), size, - last_access: SystemTime::now(), - ref_count: 1, + last_access: AtomicU64::new(unix_nanos_now()), + ref_count, }, ); - evicted + // Maintain the lock-free metric mirrors. A replaced entry cannot + // happen (we hold the construction lock and just re-checked), but + // account for it defensively so the mirrors can never drift. + if let Some(old) = replaced { + self.map_size_bytes.fetch_sub(old.size, Ordering::Relaxed); + } else { + self.map_entries.fetch_add(1, Ordering::Relaxed); + } + self.map_size_bytes.fetch_add(size, Ordering::Relaxed); + self.tombstone_victims(victims).await }; - Self::dispatch_evictions(evicted); + Self::dispatch_evictions(tombstones); - // Hardlink to destination (unlocked). The entry is pinned - // (`ref_count == 1`) so it cannot be evicted from under this hardlink. + // Hardlink to destination (unlocked). The entry is pinned so it + // cannot be evicted from under this hardlink. let result = hardlink_directory_tree(&cache_path, dest_path).await; - self.release_entry(&digest).await; + drop(pin); let method = result.err_tip(|| "Failed to hardlink newly cached directory")?; self.record_clone_method(method); - Ok(false) + Ok((false, size)) + } + + /// Removes a cache entry whose on-disk tree failed to materialize + /// (missing or corrupt), renames the tree to a tombstone, and deletes it + /// in the background — the same mechanism eviction uses. Without this, a + /// damaged entry would stay in the map and fail every future request for + /// its digest until it happened to be evicted. + /// + /// `pin` is the guard returned by `acquire_entry` for the failed + /// attempt: invalidation is skipped if the map now holds a DIFFERENT + /// entry for this digest (single-flight already rebuilt it), identified + /// by refcount-handle pointer identity. + async fn invalidate_entry(&self, digest: &DigestInfo, pin: &EntryPin) { + let tombstones = { + let mut cache = self.cache.write().await; + let is_same_entry = cache + .get(digest) + .is_some_and(|m| Arc::ptr_eq(&m.ref_count, &pin.ref_count)); + if !is_same_entry { + return; + } + let Some(metadata) = cache.remove(digest) else { + return; + }; + self.map_entries.fetch_sub(1, Ordering::Relaxed); + self.map_size_bytes + .fetch_sub(metadata.size, Ordering::Relaxed); + self.tombstone_victims(vec![metadata.path]).await + }; + Self::dispatch_evictions(tombstones); + } + + /// Best-effort `remove_dir_all` that treats `NotFound` as success and + /// only warns on other failures. Used to clear partially populated + /// destinations before a retry, partially built temp trees after a + /// failed construction, and stale crash leftovers before publishing. + async fn remove_tree_best_effort(path: &Path) { + if let Err(e) = fs::remove_dir_all(path).await + && e.kind() != std::io::ErrorKind::NotFound + { + warn!(?path, error = ?e, "Failed to remove partial directory tree"); + } } - /// If `digest` is cached, bumps its `ref_count` (pinning it against - /// eviction) and returns a snapshot of its on-disk path. The cache write - /// lock is released before returning, so the caller can perform unlocked - /// I/O against the returned path. Every successful `acquire_entry` MUST be - /// balanced by exactly one `release_entry`. - async fn acquire_entry(&self, digest: &DigestInfo) -> Option { - let mut cache = self.cache.write().await; - let metadata = cache.get_mut(digest)?; - metadata.last_access = SystemTime::now(); - metadata.ref_count += 1; - Some(metadata.path.clone()) + /// Allocates a process-unique scratch path under `cache_root` (temp + /// construction trees, eviction tombstones). Unique within the process + /// via a monotonic counter; leftovers from previous processes are + /// removed by the startup sweep in [`Self::new`]. + fn allocate_scratch_path(&self, prefix: &str) -> PathBuf { + let seq = self.scratch_seq.fetch_add(1, Ordering::Relaxed); + self.config.cache_root.join(format!("{prefix}{seq}")) } - /// Releases a pin taken by [`Self::acquire_entry`]. Tolerates the entry - /// having been removed from the map in the interim (it cannot have been, - /// because a non-zero `ref_count` blocks eviction, but be defensive). - async fn release_entry(&self, digest: &DigestInfo) { - let mut cache = self.cache.write().await; - if let Some(metadata) = cache.get_mut(digest) { - metadata.ref_count = metadata.ref_count.saturating_sub(1); + /// Renames each evicted tree to a unique tombstone path and returns the + /// tombstones for background deletion. + /// + /// MUST be called while still holding the cache write lock that removed + /// the victims from the map (or before the cache is shared, as in the + /// startup sweep). That ordering is what makes eviction race-free + /// against re-construction of an evicted digest: a constructor only + /// constructs after a cache re-check, the re-check needs the read lock, + /// so it is ordered after these renames — the background deletion can + /// therefore never touch a canonical path a fresh construction publishes + /// to. The rename itself is metadata-only and cheap; the expensive + /// `remove_dir_all` still happens off-lock in the background. + async fn tombstone_victims(&self, victims: Vec) -> Vec { + let mut tombstones = Vec::with_capacity(victims.len()); + for path in victims { + let tombstone = self.allocate_scratch_path(TOMBSTONE_PREFIX); + match fs::rename(&path, &tombstone).await { + Ok(()) => tombstones.push(tombstone), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // Already gone from disk; nothing to delete. + } + Err(e) => { + warn!( + ?path, + error = ?e, + "Failed to tombstone evicted directory, deleting in place" + ); + tombstones.push(path); + } + } } + tombstones + } + + /// If `digest` is cached, pins it against eviction and returns a + /// snapshot of its on-disk path, its recorded size, and the RAII pin. + /// Runs under the cache READ lock — the refcount and LRU timestamp are + /// atomics, so hits do not serialize on the write lock. The increment is + /// race-free against eviction because eviction requires the write lock, + /// which excludes every read-lock holder: an entry with an outstanding + /// pin is always observed with a non-zero count by `evict_lru`. + async fn acquire_entry(&self, digest: &DigestInfo) -> Option<(PathBuf, u64, EntryPin)> { + let cache = self.cache.read().await; + let metadata = cache.get(digest)?; + metadata + .last_access + .store(unix_nanos_now(), Ordering::Relaxed); + metadata.ref_count.fetch_add(1, Ordering::SeqCst); + Some(( + metadata.path.clone(), + metadata.size, + EntryPin { + ref_count: Arc::clone(&metadata.ref_count), + }, + )) } /// Drops the per-digest construction mutex from the stampede map once @@ -349,19 +808,111 @@ impl DirectoryCache { /// /// Each directory's final mode (0o755) is set at creation time, so no /// separate recursive permission pass is needed after construction. + /// Prefetches every `Directory` proto of `root`'s tree with a logical + /// `GetTree` traversal, following `next_page_token` when the server + /// paginates it, and keys each proto by its re-computed digest (the + /// responses carry protos, not digests). Returns `None` — meaning + /// "use the per-level fetch path" — when the feature is disabled, the + /// slow tier is not a `GrpcStore`, or the stream fails; a `Some` map + /// may also be incomplete, which `construct_directory` tolerates by + /// fetching any missing proto individually. One fetch permit covers + /// the entire paginated traversal. + async fn prefetch_tree_protos( + &self, + root: DigestInfo, + ) -> Option> { + if !self.config.experimental_get_tree_prefetch { + return None; + } + let grpc_store = self + .cas_store + .slow_store() + .downcast_ref::(None)?; + let digest_hasher = opentelemetry::Context::current() + .get::() + .map_or_else(default_digest_hasher_func, |v| *v); + let result: Result, Error> = async { + let _permit = self.acquire_fetch_permit().await?; + let mut protos = HashMap::new(); + let mut page_token = String::new(); + loop { + let mut stream = grpc_store + .get_tree(tonic::Request::new(GetTreeRequest { + instance_name: String::new(), + root_digest: Some(root.into()), + page_size: 0, + page_token, + digest_function: digest_hasher.proto_digest_func().into(), + })) + .await + .err_tip(|| "in prefetch_tree_protos")? + .into_inner(); + let mut next_page_token = String::new(); + while let Some(response) = stream + .message() + .await + .map_err(Error::from) + .err_tip(|| "reading GetTree stream in prefetch_tree_protos")? + { + next_page_token = response.next_page_token; + for directory in response.directories { + // GetTree yields protos without digests; recompute with + // the caller's digest function so lookups match the + // digests embedded in parent directories. + let encoded = directory.encode_to_vec(); + let mut hasher = digest_hasher.hasher(); + hasher.update(&encoded); + protos.insert(hasher.finalize_digest(), directory); + } + } + if next_page_token.is_empty() { + break; + } + page_token = next_page_token; + } + Ok(protos) + } + .await; + match result { + Ok(protos) => { + trace!(?root, protos = protos.len(), "GetTree prefetch complete"); + Some(protos) + } + Err(err) => { + debug!( + ?err, + ?root, + "GetTree prefetch failed; using per-level fetches" + ); + None + } + } + } + fn construct_directory<'a>( &'a self, digest: DigestInfo, dest_path: &'a Path, + protos: Option<&'a HashMap>, + lease: Option<&'a dyn DigestLease>, ) -> Pin> + Send + 'a>> { Box::pin(async move { debug!(?digest, ?dest_path, "Constructing directory"); - - // Fetch the Directory proto - let directory: ProtoDirectory = + // The root is reserved by `get_or_create_entry`; child digests are + // reserved before their recursive futures are queued below. + + // Use the prefetched proto when available; otherwise fetch it + // (permit held only for the fetch). A prefetch-map miss (e.g. + // an incomplete GetTree response) degrades to the fetch path. + let prefetched = protos.and_then(|map| map.get(&digest)); + let directory: ProtoDirectory = if let Some(directory) = prefetched { + directory.clone() + } else { + let _permit = self.acquire_fetch_permit().await?; get_and_decode_digest(self.cas_store.as_ref(), digest.into()) .await - .err_tip(|| format!("Failed to fetch directory digest: {digest:?}"))?; + .err_tip(|| format!("Failed to fetch directory digest: {digest:?}"))? + }; // Create the destination directory. It must be writable while it // is being populated; 0o755 is its final mode too, so set it now @@ -369,25 +920,51 @@ impl DirectoryCache { self.create_dir_writable(dest_path).await?; let mut total_size: u64 = 0; - - // Process files for file in &directory.files { - self.create_file(dest_path, file).await?; if let Some(file_digest) = &file.digest { // size_bytes is non-negative; clamp defensively. total_size += u64::try_from(file_digest.size_bytes).unwrap_or(0); + if let Ok(file_digest) = DigestInfo::try_from(file_digest) { + acquire_digest(lease, &file_digest); + } } } - // Process subdirectories recursively + // Materialize all nodes of this directory level concurrently, + // sharing one concurrency budget — the same shape as + // `download_to_directory`. Every file that is not in the fast + // tier pays a full slow-store round trip, so awaiting nodes + // sequentially serializes N round trips and dominates cold-cache + // construction time for large trees. Futures yield the subtree + // size they materialized (0 for files, whose sizes are already + // summed from their digests above, and for symlinks). + let mut node_futures: Vec>> = Vec::with_capacity( + directory.files.len() + directory.directories.len() + directory.symlinks.len(), + ); + for file in &directory.files { + node_futures.push(Box::pin(async move { + self.create_file(dest_path, file).await.map(|()| 0) + })); + } for dir_node in &directory.directories { - total_size += self.create_subdirectory(dest_path, dir_node).await?; + if let Some(dir_digest) = &dir_node.digest + && let Ok(dir_digest) = DigestInfo::try_from(dir_digest) + { + acquire_digest(lease, &dir_digest); + } + node_futures.push(Box::pin( + self.create_subdirectory(dest_path, dir_node, protos, lease), + )); } - - // Process symlinks for symlink in &directory.symlinks { - self.create_symlink(dest_path, symlink).await?; + node_futures.push(Box::pin(async move { + self.create_symlink(dest_path, symlink).await.map(|()| 0) + })); } + total_size += futures::stream::iter(node_futures) + .buffer_unordered(CONSTRUCT_DIRECTORY_CONCURRENCY) + .try_fold(0u64, |acc, size| async move { Ok(acc + size) }) + .await?; Ok(total_size) }) @@ -496,11 +1073,15 @@ impl DirectoryCache { file_path: &Path, ) -> Result<(), Error> { // Ensure the blob is in the fast (filesystem) tier so it has an - // on-disk file we can hardlink. - self.cas_store - .populate_fast_store(StoreKey::Digest(*digest)) - .await - .err_tip(|| format!("Failed to populate fast store for {digest}"))?; + // on-disk file we can hardlink. This may fetch from the slow store, + // so it holds a fetch permit. + { + let _permit = self.acquire_fetch_permit().await?; + self.cas_store + .populate_fast_store(StoreKey::Digest(*digest)) + .await + .err_tip(|| format!("Failed to populate fast store for {digest}"))?; + } let file_entry = filesystem_store .get_file_entry_for_digest(digest) @@ -530,11 +1111,13 @@ impl DirectoryCache { file_path: &Path, executable: bool, ) -> Result<(), Error> { - let data = self - .cas_store - .get_part_unchunked(StoreKey::Digest(*digest), 0, None) - .await - .err_tip(|| format!("Failed to fetch file: {}", file_path.display()))?; + let data = { + let _permit = self.acquire_fetch_permit().await?; + self.cas_store + .get_part_unchunked(StoreKey::Digest(*digest), 0, None) + .await + .err_tip(|| format!("Failed to fetch file: {}", file_path.display()))? + }; fs::write(file_path, data.as_ref()) .await @@ -562,10 +1145,20 @@ impl DirectoryCache { /// Creates a subdirectory from a `DirectoryNode`, returning the total size /// of the subtree it materializes. + /// + /// With `experimental_subtree_caching` enabled, the subtree is looked up + /// in (and inserted into) the cache by its own `Directory` digest, so a + /// subtree already constructed under any previous root is one + /// `hardlink_directory_tree` call instead of a full recursive rebuild. + /// When disabled (the default), the subtree is always constructed + /// directly under the parent with no cache interaction — today's + /// behavior, unchanged. async fn create_subdirectory( &self, parent: &Path, dir_node: &DirectoryNode, + protos: Option<&HashMap>, + lease: Option<&dyn DigestLease>, ) -> Result { let dir_path = parent.join(&dir_node.name); let digest = @@ -576,8 +1169,37 @@ impl DirectoryCache { trace!(?dir_path, ?digest, "Creating subdirectory"); + if self.config.experimental_subtree_caching { + // Subtree caching: look the subtree up in (and insert it into) + // the cache by its own digest through the same core flow root + // materializations use. REAPI `Directory` nodes are + // content-addressed, so a subtree digest seen under one root is + // byte-identical wherever else it appears; construction recurses + // through this method, so nested subtrees get their own entries + // too (leaf-level reuse). + let (hit, _size) = self + .get_or_create_entry(digest, &dir_path, protos, false, lease) + .await?; + let counter = if hit { + &self.subtree_hits + } else { + &self.subtree_misses + }; + counter.fetch_add(1, Ordering::Relaxed); + // The child's cache entry owns its bytes: contribute 0 to the + // parent's recorded size, so an entry's size covers only bytes + // not owned by a descendant entry and the sum over the map + // approximates unique materialized bytes. Counting the real + // subtree size here instead would tally every file once per + // ancestor level (~depth-fold inflation of `max_size_bytes` + // pressure) and make the cache self-defeat via phantom + // evictions. + return Ok(0); + } + // Recursively construct subdirectory - self.construct_directory(digest, &dir_path).await + self.construct_directory(digest, &dir_path, protos, lease) + .await } /// Creates a symlink from a `SymlinkNode` @@ -623,7 +1245,7 @@ impl DirectoryCache { // Check entry count while cache.len() >= self.config.max_entries { - let Some((_size, path)) = Self::evict_lru(cache) else { + let Some((e_size, path)) = Self::evict_lru(cache) else { // nothing evictable (all entries pinned) — have to exit warn!( current_items = cache.len(), @@ -632,6 +1254,9 @@ impl DirectoryCache { ); break; }; + self.evictions.fetch_add(1, Ordering::Relaxed); + self.map_entries.fetch_sub(1, Ordering::Relaxed); + self.map_size_bytes.fetch_sub(e_size, Ordering::Relaxed); evicted_paths.push(path); } @@ -650,6 +1275,9 @@ impl DirectoryCache { ); break; }; + self.evictions.fetch_add(1, Ordering::Relaxed); + self.map_entries.fetch_sub(1, Ordering::Relaxed); + self.map_size_bytes.fetch_sub(e_size, Ordering::Relaxed); size_after -= e_size; evicted_paths.push(path); } @@ -669,8 +1297,8 @@ impl DirectoryCache { ) -> Option<(u64, PathBuf)> { let to_evict = cache .iter() - .filter(|(_, m)| m.ref_count == 0) - .min_by_key(|(_, m)| m.last_access) + .filter(|(_, m)| m.ref_count.load(Ordering::SeqCst) == 0) + .min_by_key(|(_, m)| m.last_access.load(Ordering::Relaxed)) .map(|(digest, _)| *digest)?; let metadata = cache.remove(&to_evict)?; debug!( @@ -696,10 +1324,21 @@ impl DirectoryCache { } background_spawn!("directory_cache_evict", async move { for path in paths { - if !path.exists() { - // Already gone (e.g. a prior cleanup, or the cache root - // was torn down). Nothing to do, and not an error. - continue; + match fs::metadata(&path).await { + Err(_) => { + // Already gone (e.g. a prior cleanup, or the cache + // root was torn down). Nothing to do, not an error. + continue; + } + Ok(metadata) if !metadata.is_dir() => { + // Stray file (only plausible from an orphan sweep of + // a polluted cache root). + if let Err(e) = fs::remove_file(&path).await { + warn!(?path, error = ?e, "Failed to remove evicted file from disk"); + } + continue; + } + Ok(_) => {} } if let Err(e) = set_dir_writable_recursive(&path).await { warn!( @@ -728,7 +1367,10 @@ impl DirectoryCache { pub async fn stats(&self) -> CacheStats { let cache = self.cache.read().await; let total_size: u64 = cache.values().map(|m| m.size).sum(); - let in_use = cache.values().filter(|m| m.ref_count > 0).count(); + let in_use = cache + .values() + .filter(|m| m.ref_count.load(Ordering::SeqCst) > 0) + .count(); CacheStats { entries: cache.len(), @@ -736,10 +1378,66 @@ impl DirectoryCache { in_use_entries: in_use, clonefile_hits: self.clonefile_hits.load(Ordering::Relaxed), hardlink_hits: self.hardlink_hits.load(Ordering::Relaxed), + subtree_hits: self.subtree_hits.load(Ordering::Relaxed), + subtree_misses: self.subtree_misses.load(Ordering::Relaxed), + evictions: self.evictions.load(Ordering::Relaxed), } } } +impl MetricsComponent for DirectoryCache { + fn publish( + &self, + _kind: MetricKind, + field_metadata: MetricFieldData, + ) -> Result { + let _enter = group!(field_metadata.name).entered(); + publish!( + "clonefile_hits", + &self.clonefile_hits, + MetricKind::Counter, + "Materializations that used APFS clonefile(2) (macOS only)" + ); + publish!( + "hardlink_hits", + &self.hardlink_hits, + MetricKind::Counter, + "Materializations that used per-file hardlinks" + ); + publish!( + "subtree_hits", + &self.subtree_hits, + MetricKind::Counter, + "Subtree materializations served from the cache (experimental_subtree_caching)" + ); + publish!( + "subtree_misses", + &self.subtree_misses, + MetricKind::Counter, + "Subtree materializations that had to be constructed (experimental_subtree_caching)" + ); + publish!( + "evictions", + &self.evictions, + MetricKind::Counter, + "Cache entries removed by LRU eviction (high rate = cache thrash)" + ); + publish!( + "entries", + &self.map_entries, + MetricKind::Default, + "Current number of cached directory entries" + ); + publish!( + "total_size_bytes", + &self.map_size_bytes, + MetricKind::Default, + "Current recorded size of all cached entries in bytes" + ); + Ok(MetricPublishKnownKindData::Component) + } +} + /// Statistics about the directory cache #[derive(Debug, Clone, Copy)] pub struct CacheStats { @@ -750,6 +1448,16 @@ pub struct CacheStats { pub clonefile_hits: u64, /// Materializations that used per-file `fs::hard_link`. pub hardlink_hits: u64, + /// Subtree materializations served from the cache by digest. Always zero + /// unless `experimental_subtree_caching` is enabled. + pub subtree_hits: u64, + /// Subtree constructions not servable from the cache. Always zero unless + /// `experimental_subtree_caching` is enabled. + pub subtree_misses: u64, + /// Entries removed by LRU eviction. A high rate relative to hits means + /// the cache is thrashing and `max_entries`/`max_size_bytes` should be + /// raised. + pub evictions: u64, } #[cfg(test)] @@ -849,6 +1557,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, store).await?; @@ -937,6 +1646,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, store).await?; @@ -1175,6 +1885,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, store).await?; @@ -1241,6 +1952,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, store).await?; @@ -1319,6 +2031,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, cas_store).await?; @@ -1369,6 +2082,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, store).await?; @@ -1439,6 +2153,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, cas_store).await?; @@ -1495,6 +2210,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = DirectoryCache::new(config, cas_store).await?; let dest = temp_dir.path().join("dest"); @@ -1534,6 +2250,7 @@ mod tests { max_entries: 10, max_size_bytes: 1024 * 1024, cache_root, + ..Default::default() }; let cache = Arc::new(DirectoryCache::new(config, store).await?); @@ -1576,4 +2293,26 @@ mod tests { Ok(()) } + + #[nativelink_test] + async fn get_tree_prefetch_falls_back_without_grpc_store() -> Result<(), Error> { + // With the flag on but a non-grpc slow tier, prefetch must return + // None and construction must fall back to per-level fetches with + // identical results. + let temp_dir = TempDir::new().unwrap(); + let cache_root = temp_dir.path().join("cache"); + let (store, dir_digest) = setup_test_store(&temp_dir).await; + let config = DirectoryCacheConfig { + max_entries: 10, + max_size_bytes: 1024 * 1024, + cache_root, + experimental_get_tree_prefetch: true, + ..Default::default() + }; + let cache = DirectoryCache::new(config, store).await?; + let dest = temp_dir.path().join("dest"); + assert!(!cache.get_or_create(dir_digest, &dest).await?); + assert!(dest.join("test.txt").exists()); + Ok(()) + } } diff --git a/nativelink-worker/src/local_worker.rs b/nativelink-worker/src/local_worker.rs index cea87179f..c88ad9cbd 100644 --- a/nativelink-worker/src/local_worker.rs +++ b/nativelink-worker/src/local_worker.rs @@ -627,6 +627,9 @@ pub async fn new_local_worker( max_entries: cache_config.max_entries, max_size_bytes: cache_config.max_size_bytes, cache_root, + experimental_subtree_caching: cache_config.experimental_subtree_caching, + max_concurrent_fetches: cache_config.max_concurrent_fetches, + experimental_get_tree_prefetch: cache_config.experimental_get_tree_prefetch, }; match DirectoryCache::new(worker_cache_config, fast_slow_store.clone()).await { @@ -706,6 +709,7 @@ pub async fn new_local_worker( max_cleanup_backoff, timeout_handled_externally: config.timeout_handled_externally, directory_cache, + active_input_leases: config.experimental_active_input_leases, #[cfg(target_os = "linux")] use_namespaces, })?); @@ -888,24 +892,36 @@ impl LocalWorker, - handle: tokio::task::JoinHandle, + handle: tokio::task::JoinHandle, } #[cfg(target_os = "linux")] @@ -113,24 +121,43 @@ fn start_action_resource_usage_sampler(pgid: u32) -> ActionResourceUsageSampler let (stop_tx, stop_rx) = watch::channel(false); let handle = background_spawn!( "action_resource_usage_sampler", - sample_action_peak_memory_kb(pgid, stop_rx) + sample_action_resource_usage(pgid, stop_rx) ); ActionResourceUsageSampler { stop_tx, handle } } #[cfg(target_os = "linux")] -async fn finish_action_resource_usage_sampler(sampler: ActionResourceUsageSampler) -> Option { +async fn finish_action_resource_usage_sampler( + sampler: ActionResourceUsageSampler, +) -> Option { let _ = sampler.stop_tx.send(true); sampler.handle.await.ok() } #[cfg(target_os = "linux")] -async fn sample_action_peak_memory_kb(pgid: u32, mut stop_rx: watch::Receiver) -> u64 { +async fn sample_action_resource_usage( + pgid: u32, + mut stop_rx: watch::Receiver, +) -> SampledResourceUsage { let mut peak_memory_kb = 0; + // CPU time is cumulative per process and a process that exits stops + // appearing, so summing the live group at the end would lose everything + // short-lived. Keep the last figure seen for each pid and total them at + // the end instead. + let mut cpu_ticks_by_pid = HashMap::new(); + + let sample = |peak_memory_kb: &mut u64, cpu_ticks_by_pid: &mut HashMap| { + let observed = sample_process_group(pgid, cpu_ticks_by_pid); + if let Some(memory_kb) = observed { + *peak_memory_kb = (*peak_memory_kb).max(memory_kb); + } + observed + }; + loop { - if let Some(memory_kb) = sample_process_group_memory_kb(pgid) { - peak_memory_kb = peak_memory_kb.max(memory_kb); - } else if !Path::new(&format!("/proc/{pgid}")).exists() { + if sample(&mut peak_memory_kb, &mut cpu_ticks_by_pid).is_none() + && !Path::new(&format!("/proc/{pgid}")).exists() + { // The group leader has been reaped and no member process remains, // so the action is finished. break; @@ -143,16 +170,31 @@ async fn sample_action_peak_memory_kb(pgid: u32, mut stop_rx: watch::Receiver { if changed.is_ok() && *stop_rx.borrow() { - if let Some(memory_kb) = sample_process_group_memory_kb(pgid) { - peak_memory_kb = peak_memory_kb.max(memory_kb); - } + sample(&mut peak_memory_kb, &mut cpu_ticks_by_pid); break; } } () = tokio::time::sleep(RESOURCE_USAGE_SAMPLE_INTERVAL) => {} } } - peak_memory_kb + + SampledResourceUsage { + peak_memory_kb, + cpu_time_ms: ticks_to_millis(cpu_ticks_by_pid.values().sum()), + } +} + +/// Converts clock ticks from `/proc` into milliseconds. +/// +/// `_SC_CLK_TCK` is 100 on every Linux we run on, but it is queryable so ask +/// rather than assume, and fall back to 100 if the query fails. +#[cfg(target_os = "linux")] +fn ticks_to_millis(ticks: u64) -> u64 { + // SAFETY: `sysconf` takes an int and returns a long, with no memory + // safety considerations. + let hz = unsafe { libc::sysconf(libc::_SC_CLK_TCK) }; + let hz = if hz > 0 { hz as u64 } else { 100 }; + ticks.saturating_mul(1_000) / hz } /// Sums the resident memory of every process in the action's process group. @@ -167,7 +209,7 @@ async fn sample_action_peak_memory_kb(pgid: u32, mut stop_rx: watch::Receiver Option { +fn sample_process_group(pgid: u32, cpu_ticks_by_pid: &mut HashMap) -> Option { let Ok(entries) = std::fs::read_dir("/proc") else { return None; }; @@ -178,9 +220,18 @@ fn sample_process_group_memory_kb(pgid: u32) -> Option { let Ok(member_pid) = entry.file_name().to_string_lossy().parse::() else { continue; }; - if read_process_pgid(member_pid) != Some(pgid) { + let Ok(stat) = std::fs::read_to_string(format!("/proc/{member_pid}/stat")) else { + continue; + }; + if parse_pgid_from_stat(&stat) != Some(pgid) { continue; } + if let Some(ticks) = parse_cpu_ticks_from_stat(&stat) { + // Monotonic per process, but a pid could in principle be reused + // within one action, so never let the figure go backwards. + let entry = cpu_ticks_by_pid.entry(member_pid).or_insert(0); + *entry = (*entry).max(ticks); + } if let Some(memory_kb) = read_process_rss_kb(member_pid) { total_kb += memory_kb; found_any_process = true; @@ -199,12 +250,6 @@ fn read_process_rss_kb(pid: u32) -> Option { }) } -/// Reads a process's group id (`pgrp`) from `/proc//stat`. -#[cfg(target_os = "linux")] -fn read_process_pgid(pid: u32) -> Option { - parse_pgid_from_stat(&std::fs::read_to_string(format!("/proc/{pid}/stat")).ok()?) -} - /// Parses the process group id (`pgrp`, field 5) from the contents of a /// `/proc//stat` line. /// @@ -218,6 +263,28 @@ pub fn parse_pgid_from_stat(stat: &str) -> Option { after_comm.split_whitespace().nth(2)?.parse().ok() } +/// Sums user and system CPU ticks (`utime` + `stime`, fields 14 and 15) from +/// the contents of a `/proc//stat` line. +/// +/// Parsed relative to the final `)` for the same reason as the pgid above: +/// `comm` can contain spaces and parentheses. Returns `None` when the line is +/// malformed. +/// +/// `cutime`/`cstime` are deliberately not included. They only cover children +/// this process has already reaped, so adding them here would double count +/// every child that is still its own entry in the group. +#[cfg(target_os = "linux")] +pub fn parse_cpu_ticks_from_stat(stat: &str) -> Option { + let after_comm = stat.rsplit_once(')')?.1; + let mut fields = after_comm.split_whitespace(); + // Fields after the final ')': state(0) ppid(1) pgrp(2) session(3) tty(4) + // tpgid(5) flags(6) minflt(7) cminflt(8) majflt(9) cmajflt(10) + // utime(11) stime(12) ... + let utime: u64 = fields.nth(11)?.parse().ok()?; + let stime: u64 = fields.next()?.parse().ok()?; + Some(utime.saturating_add(stime)) +} + /// Valid string reasons for a failure. /// Note: If these change, the documentation should be updated. #[derive(Debug, Deserialize)] @@ -285,6 +352,97 @@ fn persistent_worker_request_arguments(argv: &[String]) -> Vec { /// overhead. const DOWNLOAD_TO_DIRECTORY_CONCURRENCY: usize = 64; +/// Keeps every digest used by an action present in locally eviction-managed +/// CAS tiers. +/// +/// A lease is registered before a digest is populated. This is important for +/// blobs that are not yet in the fast tier: reserving the key first prevents +/// the insertion that follows from immediately evicting the blob under pressure. +/// Every directly discoverable filesystem tier of the worker's +/// `FastSlowStore` is leased when present (including a `RefStore` target). +/// Transforming wrappers remain opaque by design. The reference count lets +/// concurrent actions share a digest safely. +#[derive(Debug)] +struct ActionInputLease { + filesystem_stores: Vec>, + digests: Mutex>>, +} + +impl ActionInputLease { + fn new( + cas_store: &FastSlowStore, + command_digest: DigestInfo, + input_root_digest: DigestInfo, + ) -> Arc { + let lease = Arc::new(Self { + filesystem_stores: cas_store.get_filesystem_stores(), + digests: Mutex::new(Some(HashSet::new())), + }); + lease.lease_digest(&command_digest); + lease.lease_digest(&input_root_digest); + lease + } + + fn lease_digest(&self, digest: &DigestInfo) { + let mut digests = self.digests.lock(); + let Some(digests) = digests.as_mut() else { + return; + }; + if digests.insert(*digest) { + for filesystem_store in &self.filesystem_stores { + filesystem_store.lease_digest(digest); + } + } + } + + fn take_release_work(&self) -> Option<(Vec>, Vec)> { + let digests = self.digests.lock().take()?.into_iter().collect(); + Some((self.filesystem_stores.clone(), digests)) + } + + fn spawn_release(&self) -> Option> { + let (filesystem_stores, digests) = self.take_release_work()?; + Some(background_spawn!( + "action_input_lease_release", + release_filesystem_stores(filesystem_stores, digests) + )) + } + + async fn release(self: Arc) { + let Some(handle) = self.spawn_release() else { + return; + }; + // Detach the actual release before awaiting it so cancellation of the + // action cleanup future cannot strand leases in a later filesystem + // tier. + let _result = handle.await; + } +} + +impl crate::directory_cache::DigestLease for ActionInputLease { + fn acquire(&self, digest: &DigestInfo) { + self.lease_digest(digest); + } +} + +impl Drop for ActionInputLease { + fn drop(&mut self) { + drop(self.spawn_release()); + } +} + +async fn release_filesystem_stores( + filesystem_stores: Vec>, + digests: Vec, +) { + join_all( + filesystem_stores + .iter() + .map(|filesystem_store| filesystem_store.release_digests(&digests)), + ) + .await; +} + /// Aggressively download the digests of files and make a local folder from it. This function /// gates each directory level to at most `DOWNLOAD_TO_DIRECTORY_CONCURRENCY` /// concurrent in-flight materialization futures. @@ -300,8 +458,21 @@ pub fn download_to_directory<'a>( filesystem_store: Pin<&'a FilesystemStore>, digest: &'a DigestInfo, current_directory: &'a str, +) -> BoxFuture<'a, Result<(), Error>> { + download_to_directory_with_lease(cas_store, filesystem_store, digest, current_directory, None) +} + +fn download_to_directory_with_lease<'a>( + cas_store: &'a FastSlowStore, + filesystem_store: Pin<&'a FilesystemStore>, + digest: &'a DigestInfo, + current_directory: &'a str, + input_lease: Option>, ) -> BoxFuture<'a, Result<(), Error>> { async move { + if let Some(input_lease) = &input_lease { + input_lease.lease_digest(digest); + } let directory = get_and_decode_digest::(cas_store, digest.into()) .await .err_tip(|| "Converting digest to Directory")?; @@ -319,6 +490,9 @@ pub fn download_to_directory<'a>( Some(properties) => (properties.mtime, properties.unix_mode), None => (None, None), }; + if let Some(input_lease) = &input_lease { + input_lease.lease_digest(&digest); + } futures.push( cas_store .populate_fast_store(digest.into()) @@ -467,16 +641,25 @@ pub fn download_to_directory<'a>( .try_into() .err_tip(|| "In Directory::file::digest")?; let new_directory_path = format!("{}/{}", current_directory, directory.name); + if let Some(input_lease) = &input_lease { + // Reserve queued child directories before their futures are + // polled. Without this, a large parent can leave later + // directory digests exposed to slow-tier eviction while the + // first batch of children is being materialized. + input_lease.lease_digest(&digest); + } + let input_lease = input_lease.clone(); futures.push( async move { fs::create_dir(&new_directory_path) .await .err_tip(|| format!("Could not create directory {new_directory_path}"))?; - download_to_directory( + download_to_directory_with_lease( cas_store, filesystem_store, &digest, &new_directory_path, + input_lease, ) .await .err_tip(|| format!("in download_to_directory : {new_directory_path}"))?; @@ -536,7 +719,30 @@ pub async fn prepare_action_inputs( digest: &DigestInfo, work_directory: &str, ) -> Result<(), Error> { - // Try cache first if available + prepare_action_inputs_with_lease( + directory_cache, + cas_store, + filesystem_store, + digest, + work_directory, + None, + ) + .await +} + +async fn prepare_action_inputs_with_lease( + directory_cache: &Option>, + cas_store: &FastSlowStore, + filesystem_store: Pin<&FilesystemStore>, + digest: &DigestInfo, + work_directory: &str, + input_lease: Option>, +) -> Result<(), Error> { + // Try cache first if available. Cache hits are safe while an action lease + // is active because the directory cache pins its own materialized tree + // across the hardlink operation. On a miss, pass the action lease into + // cache construction so every CAS digest is reserved before it is + // fetched/populated. if let Some(cache) = directory_cache { // `clonefile(2)` and `hardlink_directory_tree` both require the // destination to not exist. Remove the empty directory the caller @@ -545,10 +751,20 @@ pub async fn prepare_action_inputs( fs::remove_dir(work_directory) .await .err_tip(|| format!("Failed to clear pre-created work directory {work_directory}"))?; - match cache - .get_or_create(*digest, Path::new(work_directory)) - .await - { + let cache_result = if let Some(input_lease) = &input_lease { + cache + .get_or_create_with_lease( + *digest, + Path::new(work_directory), + Some(input_lease.as_ref()), + ) + .await + } else { + cache + .get_or_create(*digest, Path::new(work_directory)) + .await + }; + match cache_result { Ok(cache_hit) => { // The materialized tree is already usable. The directory // cache locks each entry down with `set_readonly_recursive`, @@ -586,7 +802,14 @@ pub async fn prepare_action_inputs( } // Traditional path (cache disabled or failed) - download_to_directory(cas_store, filesystem_store, digest, work_directory).await + download_to_directory_with_lease( + cas_store, + filesystem_store, + digest, + work_directory, + input_lease, + ) + .await } #[cfg(target_family = "windows")] @@ -866,9 +1089,11 @@ fn upload_directory<'a, P: AsRef + Debug + Send + Sync + Clone + 'a>( } } - let (mut file_nodes, dir_entries, mut symlinks) = try_join3( + let dir_entries = dir_futures + .try_collect::)>>() + .await?; + let (mut file_nodes, mut symlinks) = try_join( file_futures.try_collect::>(), - dir_futures.try_collect::)>>(), symlink_futures.try_collect::>(), ) .await?; @@ -1037,6 +1262,9 @@ pub struct RunningActionImpl { action_directory: String, work_directory: String, action_info: ActionInfo, + /// `Some` only when the manager was configured with + /// `experimental_active_input_leases`; `None` leaves eviction untouched. + input_lease: Option>, timeout: Duration, running_actions_manager: Arc, state: Mutex, @@ -1054,12 +1282,20 @@ impl RunningActionImpl { running_actions_manager: Arc, ) -> Self { let work_directory = format!("{}/{}", action_directory, "work"); + let input_lease = running_actions_manager.active_input_leases.then(|| { + ActionInputLease::new( + running_actions_manager.cas_store.as_ref(), + action_info.command_digest, + action_info.input_root_digest, + ) + }); let (kill_channel_tx, kill_channel_rx) = oneshot::channel(); Self { operation_id, action_directory, work_directory, action_info, + input_lease, timeout, running_actions_manager, state: Mutex::new(RunningActionImplState { @@ -1072,8 +1308,10 @@ impl RunningActionImpl { execution_metadata, error: None, }), - // Always need to ensure that we're removed from the manager on Drop. - has_manager_entry: AtomicBool::new(true), + // Set to true only after the action is inserted into the manager. + // The constructor can fail the operation-id uniqueness check + // immediately after this object is created. + has_manager_entry: AtomicBool::new(false), // Only needs to be cleaned up after a prepare_action call, set there. did_cleanup: AtomicBool::new(true), } @@ -1122,12 +1360,13 @@ impl RunningActionImpl { // Use directory cache if available for better performance. self.metrics() .download_to_directory - .wrap(prepare_action_inputs( + .wrap(prepare_action_inputs_with_lease( &self.running_actions_manager.directory_cache, &self.running_actions_manager.cas_store, filesystem_store_pin, &self.action_info.input_root_digest, &self.work_directory, + self.input_lease.clone(), )) .await }) @@ -1459,23 +1698,26 @@ impl RunningActionImpl { #[cfg(target_os = "linux")] { let use_namespaces = self.running_actions_manager.use_namespaces; - let root_action_directory = - std::ffi::CString::new(self.running_actions_manager.root_action_directory.clone()) - .err_tip(|| "In RunningActionImpl::inner_execute()")?; - let action_directory = std::ffi::CString::new(self.action_directory.clone()) + + if !matches!(use_namespaces, UseNamespaces::No) { + let root_action_directory = std::ffi::CString::new( + self.running_actions_manager.root_action_directory.clone(), + ) .err_tip(|| "In RunningActionImpl::inner_execute()")?; + let action_directory = std::ffi::CString::new(self.action_directory.clone()) + .err_tip(|| "In RunningActionImpl::inner_execute()")?; - // SAFETY: This function is specifically designed to operate in a async-signal-safe - // environment. - unsafe { - command_builder.pre_exec(move || match use_namespaces { - UseNamespaces::No => Ok(()), - _ => crate::namespace_utils::configure_namespace( - matches!(use_namespaces, UseNamespaces::YesAndMount), - &root_action_directory, - &action_directory, - ), - }); + // SAFETY: This function is specifically designed to operate in a async-signal-safe + // environment. + unsafe { + command_builder.pre_exec(move || { + crate::namespace_utils::configure_namespace( + matches!(use_namespaces, UseNamespaces::YesAndMount), + &root_action_directory, + &action_directory, + ) + }); + } } // Run the action as its own process-group leader (pgid == child @@ -1640,13 +1882,19 @@ impl RunningActionImpl { let resource_usage = match maybe_resource_usage_sampler.take() { Some(sampler) => finish_action_resource_usage_sampler(sampler) .await - .and_then(|peak_memory_kb| { - (peak_memory_kb > 0).then_some(ActionResourceUsage { - peak_memory_kb, - sampled: true, - operation_id: String::new(), - worker_id: String::new(), - }) + .and_then(|usage| { + // An action too short to catch a sample leaves + // both at zero; report nothing rather than a + // misleading zero. + (usage.peak_memory_kb > 0 || usage.cpu_time_ms > 0).then_some( + ActionResourceUsage { + peak_memory_kb: usage.peak_memory_kb, + cpu_time_ms: usage.cpu_time_ms, + sampled: true, + operation_id: String::new(), + worker_id: String::new(), + }, + ) }), None => None, }; @@ -2089,6 +2337,12 @@ impl Drop for RunningActionImpl { .cleanup_action(&self.operation_id), ); } + if let Some(input_lease) = self.input_lease.clone() { + background_spawn!( + "running_action_impl_release_input_lease", + input_lease.release() + ); + } return; } let operation_id = self.operation_id.clone(); @@ -2098,18 +2352,21 @@ impl Drop for RunningActionImpl { ); let running_actions_manager = self.running_actions_manager.clone(); let action_directory = self.action_directory.clone(); + let input_lease = self.input_lease.clone(); background_spawn!("running_action_impl_drop", async move { - let Err(err) = - do_cleanup(&running_actions_manager, &operation_id, &action_directory).await - else { - return; - }; - error!( - %operation_id, - ?action_directory, - ?err, - "Error cleaning up action" - ); + let cleanup_result = + do_cleanup(&running_actions_manager, &operation_id, &action_directory).await; + if let Some(input_lease) = input_lease { + input_lease.release().await; + } + if let Err(err) = cleanup_result { + error!( + %operation_id, + ?action_directory, + ?err, + "Error cleaning up action" + ); + } }); } } @@ -2209,6 +2466,13 @@ impl RunningAction for RunningActionImpl { .await; self.has_manager_entry.store(false, Ordering::Release); self.did_cleanup.store(true, Ordering::Release); + // The work directory and manager entry are gone before the + // lease is released. If this future is cancelled while the + // release task is finishing, Drop still observes a completed + // cleanup and cannot strand the action in the manager. + if let Some(input_lease) = self.input_lease.clone() { + input_lease.release().await; + } result.map(move |()| self) }) .await; @@ -2564,6 +2828,11 @@ pub struct RunningActionsManagerArgs<'a> { pub max_cleanup_backoff: Duration, pub timeout_handled_externally: bool, pub directory_cache: Option>, + /// When true, every digest in an active action's input Merkle closure is + /// leased in the locally eviction-managed CAS tiers until the action's + /// cleanup completes. While leases are held, those tiers may temporarily + /// exceed their configured `max_bytes` / `max_count` eviction limits. + pub active_input_leases: bool, #[cfg(target_os = "linux")] pub use_namespaces: UseNamespaces, } @@ -2617,6 +2886,9 @@ pub struct RunningActionsManagerImpl { /// Optional directory cache for improving performance by caching reconstructed /// input directories and using hardlinks. directory_cache: Option>, + /// Whether active action inputs are leased against eviction in the local + /// CAS tiers (opt-in via `experimental_active_input_leases`). + active_input_leases: bool, persistent_worker_pool: PersistentWorkerPool, } @@ -2653,12 +2925,16 @@ impl RunningActionsManagerImpl { running_actions: Mutex::new(HashMap::new()), action_done_tx, callbacks, - metrics: Arc::new(Metrics::default()), + metrics: Arc::new(Metrics { + directory_cache: args.directory_cache.as_ref().map(Arc::downgrade), + ..Default::default() + }), cleaning_up_operations: Mutex::new(HashSet::new()), max_cleanup_wait: args.max_cleanup_wait, max_cleanup_backoff: args.max_cleanup_backoff, cleanup_complete_notify: Arc::new(Notify::new()), directory_cache: args.directory_cache, + active_input_leases: args.active_input_leases, persistent_worker_pool: PersistentWorkerPool::default(), #[cfg(target_os = "linux")] use_namespaces: args.use_namespaces, @@ -2690,6 +2966,20 @@ impl RunningActionsManagerImpl { }; if !should_wait { + let action_is_running = self + .running_actions + .lock() + .get(operation_id) + .and_then(Weak::upgrade) + .is_some(); + if action_is_running { + return Err(make_err!( + Code::AlreadyExists, + "Action with operation_id {} is already running", + operation_id + )); + } + let dir_path = PathBuf::from(&self.root_action_directory).join(operation_id.to_string()); @@ -2930,6 +3220,9 @@ impl RunningActionsManager for RunningActionsManagerImpl { )); } running_actions.insert(operation_id, Arc::downgrade(&running_action)); + running_action + .has_manager_entry + .store(true, Ordering::Release); } Ok(running_action) }) @@ -2971,10 +3264,7 @@ impl RunningActionsManager for RunningActionsManagerImpl { .wrap_no_capture_result(async move { let kill_operations: Vec> = { let running_actions = self.running_actions.lock(); - running_actions - .iter() - .filter_map(|(_operation_id, action)| action.upgrade()) - .collect() + running_actions.values().filter_map(Weak::upgrade).collect() }; let mut kill_futures: FuturesUnordered<_> = kill_operations .into_iter() @@ -3048,4 +3338,8 @@ pub struct Metrics { upload_stderr: AsyncCounterWrapper, #[metric(help = "Total number of task timeouts.")] task_timeouts: CounterWithTime, + #[metric( + help = "Stats about the input-directory cache (hits, misses, subtree reuse, evictions, size)." + )] + directory_cache: Option>, } diff --git a/nativelink-worker/tests/directory_cache_stress_test.rs b/nativelink-worker/tests/directory_cache_stress_test.rs new file mode 100644 index 000000000..8358f73b7 --- /dev/null +++ b/nativelink-worker/tests/directory_cache_stress_test.rs @@ -0,0 +1,447 @@ +// Stress/regression test for DirectoryCache concurrent construction. +// Exercises: +// - single-flight stampede (many tasks requesting the same root digest) +// - concurrent distinct constructions +// - eviction churn racing construction (tiny max_entries) +// - shared file digests across trees (hardlink inode sharing) +// - executables (copy path), symlinks, and empty files (zero-digest path) +// - jittered slow-tier latency; records peak global in-flight fetches +// Verifies every materialized tree byte-for-byte afterwards. + +use core::pin::Pin; +use core::sync::atomic::{AtomicU64, Ordering}; +use core::time::Duration; +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::time::Instant; + +use async_trait::async_trait; +use bytes::Bytes; +use nativelink_config::stores::{ + FastSlowSpec, FilesystemSpec, MemorySpec, StoreDirection, StoreSpec, +}; +use nativelink_error::Error; +use nativelink_macro::nativelink_test; +use nativelink_metric::{ + MetricFieldData, MetricKind, MetricPublishKnownKindData, MetricsComponent, +}; +use nativelink_proto::build::bazel::remote::execution::v2::{ + Directory as ProtoDirectory, DirectoryNode, FileNode, SymlinkNode, +}; +use nativelink_store::fast_slow_store::FastSlowStore; +use nativelink_store::filesystem_store::FilesystemStore; +use nativelink_store::memory_store::MemoryStore; +use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; +use nativelink_util::common::{DigestInfo, make_temp_path}; +use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; +use nativelink_util::store_trait::{ + RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, +}; +use nativelink_worker::directory_cache::{DirectoryCache, DirectoryCacheConfig}; +use prost::Message; +use uuid::Uuid; + +const BASE_RTT_MS: u64 = 5; +const JITTER_MS: u64 = 10; + +#[derive(Debug)] +struct JitteredDelayStore { + inner: Store, + fetches: AtomicU64, + in_flight: AtomicU64, + peak_in_flight: AtomicU64, +} + +impl JitteredDelayStore { + fn new(inner: Arc) -> Arc { + Arc::new(Self { + inner: Store::new(inner), + fetches: AtomicU64::new(0), + in_flight: AtomicU64::new(0), + peak_in_flight: AtomicU64::new(0), + }) + } +} + +impl MetricsComponent for JitteredDelayStore { + fn publish( + &self, + _kind: MetricKind, + _field_metadata: MetricFieldData, + ) -> Result { + Ok(MetricPublishKnownKindData::Component) + } +} + +#[async_trait] +impl StoreDriver for JitteredDelayStore { + async fn post_init(self: Arc) -> Result<(), Error> { + Ok(()) + } + + async fn has_with_results( + self: Pin<&Self>, + keys: &[StoreKey<'_>], + results: &mut [Option], + ) -> Result<(), Error> { + self.inner + .as_store_driver_pin() + .has_with_results(keys, results) + .await + } + + async fn update( + self: Pin<&Self>, + key: StoreKey<'_>, + reader: DropCloserReadHalf, + size_info: UploadSizeInfo, + ) -> Result { + self.inner + .as_store_driver_pin() + .update(key, reader, size_info) + .await + } + + async fn get_part( + self: Pin<&Self>, + key: StoreKey<'_>, + writer: &mut DropCloserWriteHalf, + offset: u64, + length: Option, + ) -> Result<(), Error> { + self.fetches.fetch_add(1, Ordering::SeqCst); + let now = self.in_flight.fetch_add(1, Ordering::SeqCst) + 1; + self.peak_in_flight.fetch_max(now, Ordering::SeqCst); + // Deterministic per-key jitter. + let jitter = match &key { + StoreKey::Digest(d) => u64::from(d.packed_hash()[2]) % JITTER_MS, + StoreKey::Str(_) => 0, + }; + tokio::time::sleep(Duration::from_millis(BASE_RTT_MS + jitter)).await; + let result = self + .inner + .as_store_driver_pin() + .get_part(key, writer, offset, length) + .await; + self.in_flight.fetch_sub(1, Ordering::SeqCst); + result + } + + fn inner_store(&self, _key: Option) -> &dyn StoreDriver { + self + } + + fn as_any<'a>(&'a self) -> &'a (dyn core::any::Any + Sync + Send + 'static) { + self + } + + fn as_any_arc(self: Arc) -> Arc { + self + } + + fn register_remove_callback( + self: Arc, + _callback: Arc, + ) -> Result<(), Error> { + Ok(()) + } +} + +default_health_status_indicator!(JitteredDelayStore); + +/// Expected on-disk state: relative path -> (content, `is_executable`) or symlink target. +#[derive(Debug, Default)] +struct ExpectedTree { + files: HashMap, bool)>, + symlinks: HashMap, +} + +fn file_digest(tree_id: u32, idx: u32, shared: bool, content: &[u8]) -> DigestInfo { + let mut hash = [0u8; 32]; + hash[0] = 1; + // Shared digests are identical across trees; unique ones namespace by tree. + hash[1..5].copy_from_slice(&(if shared { 0 } else { tree_id + 1 }).to_le_bytes()); + hash[5..9].copy_from_slice(&idx.to_le_bytes()); + hash[9] = u8::from(shared); + DigestInfo::new(hash, content.len() as u64) +} + +/// Builds one tree seeded ONLY into the slow store. Returns root digest and +/// the expected on-disk layout. Layout per mid dir: `files_per_leaf` regular +/// files (every 5th shared across trees, every 7th executable, every 11th +/// empty) plus one symlink. +async fn seed_stress_tree( + slow_store: &Arc, + tree_id: u32, + mid_dirs: u32, + leaf_dirs: u32, + files_per_leaf: u32, +) -> Result<(DigestInfo, ExpectedTree), Error> { + let mut expected = ExpectedTree::default(); + let mut dir_seq = 0u32; + let mut mid_nodes = Vec::new(); + for m in 0..mid_dirs { + let mut leaf_nodes = Vec::new(); + for l in 0..leaf_dirs { + let mut file_nodes = Vec::new(); + let mut symlink_nodes = Vec::new(); + for f in 0..files_per_leaf { + let idx = (m * leaf_dirs + l) * files_per_leaf + f; + let shared = f % 5 == 0; + let is_executable = f % 7 == 0; + let empty = f % 11 == 3; + let content: Vec = if empty { + Vec::new() + } else if shared { + format!("shared-{idx}").into_bytes().repeat(50) + } else { + format!("tree{tree_id}-file{idx}-").into_bytes().repeat(40) + }; + let name = format!("file_{f}"); + let rel = PathBuf::from(format!("mid_{m}/leaf_{l}/{name}")); + if empty { + // Zero-digest shortcut: never stored, written directly. + // (Sha256 hash of zero bytes, matching cas_utils::ZERO_BYTE_DIGESTS.) + let digest = DigestInfo::new( + [ + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, + 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, + ], + 0, + ); + expected.files.insert(rel, (Vec::new(), false)); + file_nodes.push(FileNode { + name, + digest: Some(digest.into()), + is_executable: false, + node_properties: None, + }); + continue; + } + let digest = file_digest(tree_id, idx, shared, &content); + slow_store + .update_oneshot(digest, Bytes::from(content.clone())) + .await?; + expected.files.insert(rel, (content, is_executable)); + file_nodes.push(FileNode { + name, + digest: Some(digest.into()), + is_executable, + node_properties: None, + }); + } + // One symlink per leaf pointing at its first file (unix only: + // Windows CI runners lack symlink privileges). + if cfg!(unix) { + symlink_nodes.push(SymlinkNode { + name: "link_to_first".to_string(), + target: "file_0".to_string(), + node_properties: None, + }); + expected.symlinks.insert( + PathBuf::from(format!("mid_{m}/leaf_{l}/link_to_first")), + "file_0".to_string(), + ); + } + let leaf = ProtoDirectory { + files: file_nodes, + directories: vec![], + symlinks: symlink_nodes, + node_properties: None, + } + .encode_to_vec(); + let mut hash = [0u8; 32]; + hash[0] = 2; + hash[1..5].copy_from_slice(&(tree_id + 1).to_le_bytes()); + hash[5..9].copy_from_slice(&dir_seq.to_le_bytes()); + dir_seq += 1; + let digest = DigestInfo::new(hash, leaf.len() as u64); + slow_store.update_oneshot(digest, Bytes::from(leaf)).await?; + leaf_nodes.push(DirectoryNode { + name: format!("leaf_{l}"), + digest: Some(digest.into()), + }); + } + let mid = ProtoDirectory { + files: vec![], + directories: leaf_nodes, + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let mut hash = [0u8; 32]; + hash[0] = 3; + hash[1..5].copy_from_slice(&(tree_id + 1).to_le_bytes()); + hash[5..9].copy_from_slice(&dir_seq.to_le_bytes()); + dir_seq += 1; + let digest = DigestInfo::new(hash, mid.len() as u64); + slow_store.update_oneshot(digest, Bytes::from(mid)).await?; + mid_nodes.push(DirectoryNode { + name: format!("mid_{m}"), + digest: Some(digest.into()), + }); + } + let root = ProtoDirectory { + files: vec![], + directories: mid_nodes, + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let mut hash = [0u8; 32]; + hash[0] = 4; + hash[1..5].copy_from_slice(&(tree_id + 1).to_le_bytes()); + let digest = DigestInfo::new(hash, root.len() as u64); + slow_store.update_oneshot(digest, Bytes::from(root)).await?; + Ok((digest, expected)) +} + +async fn verify_tree(dest: &Path, expected: &ExpectedTree) -> Result<(), String> { + for (rel, (content, is_executable)) in &expected.files { + let path = dest.join(rel); + let actual = tokio::fs::read(&path) + .await + .map_err(|e| format!("missing file {}: {e}", path.display()))?; + if &actual != content { + return Err(format!( + "content mismatch at {} ({} vs {} bytes)", + path.display(), + actual.len(), + content.len() + )); + } + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mode = tokio::fs::metadata(&path) + .await + .map_err(|e| format!("stat {}: {e}", path.display()))? + .permissions() + .mode(); + if *is_executable && mode & 0o111 == 0 { + return Err(format!("expected +x on {}", path.display())); + } + } + #[cfg(not(unix))] + let _ = is_executable; + } + for (rel, target) in &expected.symlinks { + let path = dest.join(rel); + let actual = tokio::fs::read_link(&path) + .await + .map_err(|e| format!("missing symlink {}: {e}", path.display()))?; + if actual.to_str() != Some(target.as_str()) { + return Err(format!("symlink target mismatch at {}", path.display())); + } + } + Ok(()) +} + +#[nativelink_test(flavor = "multi_thread", worker_threads = 8)] +async fn stress_concurrent_construction() -> Result<(), Error> { + const NUM_TREES: u32 = 4; + const MID_DIRS: u32 = 4; + const LEAF_DIRS: u32 = 4; + const FILES_PER_LEAF: u32 = 20; // 320 files/tree, 1280 total + const CONCURRENT_TASKS: u32 = 24; // 6x duplication per tree -> stampede + const MAX_ENTRIES: usize = 2; // half the trees -> constant eviction churn + + let memory_store = MemoryStore::new(&MemorySpec::default()); + let mut trees = Vec::new(); + for t in 0..NUM_TREES { + trees.push(seed_stress_tree(&memory_store, t, MID_DIRS, LEAF_DIRS, FILES_PER_LEAF).await?); + } + let delay_store = JitteredDelayStore::new(memory_store); + let stats = delay_store.clone(); + + let fast_spec = FilesystemSpec { + content_path: make_temp_path("cas_content"), + temp_path: make_temp_path("cas_temp"), + eviction_policy: None, + ..Default::default() + }; + let fast_store: Arc = FilesystemStore::new(&fast_spec).await.unwrap(); + let cas_store = FastSlowStore::new( + &FastSlowSpec { + fast: StoreSpec::Filesystem(fast_spec), + slow: StoreSpec::Memory(MemorySpec::default()), + fast_direction: StoreDirection::default(), + slow_direction: StoreDirection::default(), + bypass_dedup_threshold_bytes: 0, + }, + Store::new(fast_store), + Store::new(delay_store), + ); + + let cache = Arc::new( + DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + max_entries: MAX_ENTRIES, + ..Default::default() + }, + cas_store, + ) + .await?, + ); + + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + let trees = Arc::new(trees); + let start = Instant::now(); + let mut handles = Vec::new(); + for task in 0..CONCURRENT_TASKS { + let cache = cache.clone(); + let trees = trees.clone(); + let dest = working_directory.join(format!("task_{task}_{}", Uuid::new_v4())); + handles.push(tokio::spawn(async move { + let (root_digest, _) = &trees[(task % NUM_TREES) as usize]; + let t0 = Instant::now(); + let result = cache.get_or_create(*root_digest, &dest).await; + (task, dest, result, t0.elapsed()) + })); + } + + let mut construct_times = Vec::new(); + let mut hits = 0u32; + for handle in handles { + let (task, dest, result, elapsed) = handle.await.expect("task panicked"); + let was_hit = result.unwrap_or_else(|e| panic!("task {task} failed: {e:?}")); + if was_hit { + hits += 1; + } + construct_times.push(elapsed.as_millis()); + let (_, expected) = &trees[(task % NUM_TREES) as usize]; + if let Err(msg) = verify_tree(&dest, expected).await { + panic!("task {task} tree verification failed: {msg}"); + } + } + let wall = start.elapsed(); + + construct_times.sort_unstable(); + let p50 = construct_times[construct_times.len() / 2]; + let max = construct_times.last().unwrap(); + eprintln!("=== STRESS RESULT ==="); + eprintln!( + "tasks: {CONCURRENT_TASKS} over {NUM_TREES} trees ({} files/tree), max_entries={MAX_ENTRIES}", + MID_DIRS * LEAF_DIRS * FILES_PER_LEAF + ); + eprintln!( + "wall: {}ms, per-task p50: {p50}ms, max: {max}ms, cache hits: {hits}/{CONCURRENT_TASKS}", + wall.as_millis() + ); + eprintln!( + "slow-tier fetches: {}, peak in-flight: {}", + stats.fetches.load(Ordering::SeqCst), + stats.peak_in_flight.load(Ordering::SeqCst) + ); + eprintln!("all {CONCURRENT_TASKS} trees byte-verified OK"); + assert!( + stats.peak_in_flight.load(Ordering::SeqCst) <= 64, + "aggregate slow-tier concurrency must be bounded by the cache-wide budget" + ); + Ok(()) +} diff --git a/nativelink-worker/tests/directory_cache_test.rs b/nativelink-worker/tests/directory_cache_test.rs index 5d8a43a15..0a0f5843f 100644 --- a/nativelink-worker/tests/directory_cache_test.rs +++ b/nativelink-worker/tests/directory_cache_test.rs @@ -12,26 +12,52 @@ // See the License for the specific language governing permissions and // limitations under the License. +use core::pin::Pin; +use core::sync::atomic::{AtomicU64, Ordering}; +use core::time::Duration; +use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::sync::Arc; +use async_trait::async_trait; use bytes::Bytes; +use futures::Stream; use nativelink_config::stores::{ - FastSlowSpec, FilesystemSpec, MemorySpec, StoreDirection, StoreSpec, + FastSlowSpec, FilesystemSpec, GrpcEndpoint, GrpcSpec, MemorySpec, Retry, StoreDirection, + StoreSpec, StoreType, }; use nativelink_error::Error; use nativelink_macro::nativelink_test; +use nativelink_metric::{ + MetricFieldData, MetricKind, MetricPublishKnownKindData, MetricsComponent, +}; +use nativelink_proto::build::bazel::remote::execution::v2::content_addressable_storage_server::{ + ContentAddressableStorage, ContentAddressableStorageServer, +}; use nativelink_proto::build::bazel::remote::execution::v2::{ - Directory as ProtoDirectory, DirectoryNode, FileNode, SymlinkNode, + BatchReadBlobsRequest, BatchReadBlobsResponse, BatchUpdateBlobsRequest, + BatchUpdateBlobsResponse, Directory as ProtoDirectory, DirectoryNode, FileNode, + FindMissingBlobsRequest, FindMissingBlobsResponse, GetTreeRequest, GetTreeResponse, + SpliceBlobRequest, SpliceBlobResponse, SplitBlobRequest, SplitBlobResponse, SymlinkNode, }; use nativelink_store::fast_slow_store::FastSlowStore; use nativelink_store::filesystem_store::FilesystemStore; +use nativelink_store::grpc_store::GrpcStore; use nativelink_store::memory_store::MemoryStore; +use nativelink_util::background_spawn; +use nativelink_util::buf_channel::{DropCloserReadHalf, DropCloserWriteHalf}; use nativelink_util::common::{DigestInfo, make_temp_path}; -use nativelink_util::store_trait::{Store, StoreLike}; +use nativelink_util::digest_hasher::{DigestHasher, default_digest_hasher_func}; +use nativelink_util::health_utils::{HealthStatusIndicator, default_health_status_indicator}; +use nativelink_util::store_trait::{ + RemoveItemCallback, Store, StoreDriver, StoreKey, StoreLike, UploadSizeInfo, +}; use nativelink_worker::directory_cache::{DirectoryCache, DirectoryCacheConfig}; use prost::Message; -use tonic::Code; +use tokio::sync::Mutex; +use tonic::transport::Server; +use tonic::transport::server::TcpIncoming; +use tonic::{Code, Request, Response, Status}; use uuid::Uuid; /// Wraps a `MemoryStore` as the slow tier of a `FastSlowStore` whose fast @@ -269,3 +295,1353 @@ async fn evict_with_directory_entry() -> Result<(), Error> { )); Ok(()) } + +/// `MemoryStore` wrapper that records the maximum number of concurrent +/// `get_part` calls it has observed. Each call holds its slot briefly so +/// that overlapping fetches are reliably observed as overlapping. +#[derive(Debug)] +struct ConcurrencyTrackingStore { + inner: Store, + in_flight: AtomicU64, + max_in_flight: AtomicU64, +} + +impl ConcurrencyTrackingStore { + fn new(inner: Arc) -> Arc { + Arc::new(Self { + inner: Store::new(inner), + in_flight: AtomicU64::new(0), + max_in_flight: AtomicU64::new(0), + }) + } +} + +impl MetricsComponent for ConcurrencyTrackingStore { + fn publish( + &self, + _kind: MetricKind, + _field_metadata: MetricFieldData, + ) -> Result { + Ok(MetricPublishKnownKindData::Component) + } +} + +#[async_trait] +impl StoreDriver for ConcurrencyTrackingStore { + async fn post_init(self: Arc) -> Result<(), Error> { + Ok(()) + } + + async fn has_with_results( + self: Pin<&Self>, + keys: &[StoreKey<'_>], + results: &mut [Option], + ) -> Result<(), Error> { + self.inner + .as_store_driver_pin() + .has_with_results(keys, results) + .await + } + + async fn update( + self: Pin<&Self>, + key: StoreKey<'_>, + reader: DropCloserReadHalf, + size_info: UploadSizeInfo, + ) -> Result { + self.inner + .as_store_driver_pin() + .update(key, reader, size_info) + .await + } + + async fn get_part( + self: Pin<&Self>, + key: StoreKey<'_>, + writer: &mut DropCloserWriteHalf, + offset: u64, + length: Option, + ) -> Result<(), Error> { + let now_in_flight = self.in_flight.fetch_add(1, Ordering::SeqCst) + 1; + self.max_in_flight + .fetch_max(now_in_flight, Ordering::SeqCst); + // Hold the slot long enough for concurrent fetches to overlap. + tokio::time::sleep(Duration::from_millis(5)).await; + let result = self + .inner + .as_store_driver_pin() + .get_part(key, writer, offset, length) + .await; + self.in_flight.fetch_sub(1, Ordering::SeqCst); + result + } + + fn inner_store(&self, _key: Option) -> &dyn StoreDriver { + self + } + + fn as_any<'a>(&'a self) -> &'a (dyn core::any::Any + Sync + Send + 'static) { + self + } + + fn as_any_arc(self: Arc) -> Arc { + self + } + + fn register_remove_callback( + self: Arc, + _callback: Arc, + ) -> Result<(), Error> { + Ok(()) + } +} + +default_health_status_indicator!(ConcurrencyTrackingStore); + +/// Cold-cache construction must fetch a directory's blobs concurrently, not +/// one at a time: every fast-tier miss pays a full slow-store round trip, so +/// sequential fetches serialize N round trips (regression test for the +/// `for … await` loops `construct_directory` used to have). +#[nativelink_test] +async fn cold_construct_fetches_concurrently() -> Result<(), Error> { + const NUM_FILES: u32 = 32; + + let memory_store = MemoryStore::new(&MemorySpec::default()); + let mut file_nodes = Vec::new(); + for i in 0..NUM_FILES { + let content = format!("content-{i}").into_bytes(); + let mut hash = [0u8; 32]; + hash[0] = 1; + hash[1..5].copy_from_slice(&i.to_le_bytes()); + let digest = DigestInfo::new(hash, content.len() as u64); + memory_store + .update_oneshot(digest, Bytes::from(content)) + .await?; + file_nodes.push(FileNode { + name: format!("file_{i}"), + digest: Some(digest.into()), + is_executable: false, + node_properties: None, + }); + } + let root = ProtoDirectory { + files: file_nodes, + directories: vec![], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let root_digest = DigestInfo::new([7u8; 32], root.len() as u64); + memory_store + .update_oneshot(root_digest, Bytes::from(root)) + .await?; + + let tracking_store = ConcurrencyTrackingStore::new(memory_store); + let tracking_store_for_asserts = tracking_store.clone(); + + let fast_spec = FilesystemSpec { + content_path: make_temp_path("cas_content"), + temp_path: make_temp_path("cas_temp"), + eviction_policy: None, + ..Default::default() + }; + let fast_store: Arc = FilesystemStore::new(&fast_spec).await.unwrap(); + let cas_store = FastSlowStore::new( + &FastSlowSpec { + fast: StoreSpec::Filesystem(fast_spec), + slow: StoreSpec::Memory(MemorySpec::default()), + fast_direction: StoreDirection::default(), + slow_direction: StoreDirection::default(), + bypass_dedup_threshold_bytes: 0, + }, + Store::new(fast_store), + Store::new(tracking_store), + ); + + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + ..Default::default() + }, + cas_store, + ) + .await?; + + let working_directory = PathBuf::from(make_temp_path("working_directory")); + let hit = cache + .get_or_create( + root_digest, + working_directory.join(Uuid::new_v4().to_string()).as_path(), + ) + .await?; + assert!(!hit, "first call must be a cache miss"); + + let max_in_flight = tracking_store_for_asserts + .max_in_flight + .load(Ordering::SeqCst); + assert!( + max_in_flight > 1, + "expected concurrent slow-store fetches during cold construction, \ + but max in-flight was {max_in_flight}" + ); + Ok(()) +} + +/// SHA-256 of zero bytes, matching `cas_utils::ZERO_BYTE_DIGESTS`. Never +/// stored in the CAS; `DirectoryCache` writes such files directly. +fn empty_file_digest() -> DigestInfo { + DigestInfo::try_new( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + 0, + ) + .unwrap() +} + +/// Expected on-disk state for a seeded tree: relative path -> (content, +/// `is_executable`), plus symlink targets. +#[derive(Debug, Default)] +struct ExpectedTree { + files: HashMap, bool)>, + symlinks: HashMap, +} + +/// Deterministic synthetic digest for a stress-tree file. Shared digests are +/// identical across trees; unique ones are namespaced by `tree_id`. +fn stress_file_digest(tree_id: u32, idx: u32, shared: bool, content: &[u8]) -> DigestInfo { + let mut hash = [0u8; 32]; + hash[0] = 1; + hash[1..5].copy_from_slice(&(if shared { 0 } else { tree_id + 1 }).to_le_bytes()); + hash[5..9].copy_from_slice(&idx.to_le_bytes()); + hash[9] = u8::from(shared); + DigestInfo::new(hash, content.len() as u64) +} + +/// Builds a three-level tree (root -> `mid_*` -> `leaf_*` -> files) seeded +/// ONLY into the slow store, returning the root digest and the expected +/// on-disk layout. Per leaf: `files_per_leaf` regular files (every 5th shared +/// across trees, every 7th executable, `f % 11 == 3` empty via the zero-byte +/// digest) plus one symlink on unix. +/// +/// With `mutate_one_file` set, the result is the "one changed file" variant +/// of the same tree: `mid_0/leaf_0/file_1` gets different content, so that +/// leaf, `mid_0`, and the root all get new digests while every other subtree +/// digest is byte-identical to the unmutated tree. +async fn seed_stress_tree( + slow_store: &Arc, + tree_id: u32, + mid_dirs: u32, + leaf_dirs: u32, + files_per_leaf: u32, + mutate_one_file: bool, +) -> Result<(DigestInfo, ExpectedTree), Error> { + let mut expected = ExpectedTree::default(); + let mut dir_seq = 0u32; + let mut mid_nodes = Vec::new(); + for m in 0..mid_dirs { + let mut leaf_nodes = Vec::new(); + for l in 0..leaf_dirs { + let mutated_leaf = mutate_one_file && m == 0 && l == 0; + let mut file_nodes = Vec::new(); + let mut symlink_nodes = Vec::new(); + for f in 0..files_per_leaf { + let idx = (m * leaf_dirs + l) * files_per_leaf + f; + let shared = f % 5 == 0; + let is_executable = f % 7 == 0; + let empty = f % 11 == 3; + let mutated_file = mutated_leaf && f == 1; + let name = format!("file_{f}"); + let rel = PathBuf::from(format!("mid_{m}/leaf_{l}/{name}")); + if empty { + // Zero-digest shortcut: never stored in the CAS, the + // cache writes such files directly. + expected.files.insert(rel, (Vec::new(), false)); + file_nodes.push(FileNode { + name, + digest: Some(empty_file_digest().into()), + is_executable: false, + node_properties: None, + }); + continue; + } + let content: Vec = if mutated_file { + b"MUTATED-".repeat(60) + } else if shared { + format!("shared-{idx}").into_bytes().repeat(50) + } else { + format!("tree{tree_id}-file{idx}-").into_bytes().repeat(40) + }; + let digest = if mutated_file { + let mut hash = [0u8; 32]; + hash[0] = 9; + DigestInfo::new(hash, content.len() as u64) + } else { + stress_file_digest(tree_id, idx, shared, &content) + }; + slow_store + .update_oneshot(digest, Bytes::from(content.clone())) + .await?; + expected.files.insert(rel, (content, is_executable)); + file_nodes.push(FileNode { + name, + digest: Some(digest.into()), + is_executable, + node_properties: None, + }); + } + // One symlink per leaf pointing at its first file (unix only: + // Windows CI runners lack symlink privileges). + if cfg!(unix) { + symlink_nodes.push(SymlinkNode { + name: "link_to_first".to_string(), + target: "file_0".to_string(), + node_properties: None, + }); + expected.symlinks.insert( + PathBuf::from(format!("mid_{m}/leaf_{l}/link_to_first")), + "file_0".to_string(), + ); + } + let leaf = ProtoDirectory { + files: file_nodes, + directories: vec![], + symlinks: symlink_nodes, + node_properties: None, + } + .encode_to_vec(); + let mut hash = [0u8; 32]; + if mutated_leaf { + hash[0] = 10; + } else { + hash[0] = 2; + hash[1..5].copy_from_slice(&(tree_id + 1).to_le_bytes()); + hash[5..9].copy_from_slice(&dir_seq.to_le_bytes()); + } + dir_seq += 1; + let digest = DigestInfo::new(hash, leaf.len() as u64); + slow_store.update_oneshot(digest, Bytes::from(leaf)).await?; + leaf_nodes.push(DirectoryNode { + name: format!("leaf_{l}"), + digest: Some(digest.into()), + }); + } + let mid = ProtoDirectory { + files: vec![], + directories: leaf_nodes, + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let mut hash = [0u8; 32]; + if mutate_one_file && m == 0 { + hash[0] = 11; + } else { + hash[0] = 3; + hash[1..5].copy_from_slice(&(tree_id + 1).to_le_bytes()); + hash[5..9].copy_from_slice(&dir_seq.to_le_bytes()); + } + dir_seq += 1; + let digest = DigestInfo::new(hash, mid.len() as u64); + slow_store.update_oneshot(digest, Bytes::from(mid)).await?; + mid_nodes.push(DirectoryNode { + name: format!("mid_{m}"), + digest: Some(digest.into()), + }); + } + let root = ProtoDirectory { + files: vec![], + directories: mid_nodes, + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let mut hash = [0u8; 32]; + hash[0] = if mutate_one_file { 12 } else { 4 }; + hash[1..5].copy_from_slice(&(tree_id + 1).to_le_bytes()); + let digest = DigestInfo::new(hash, root.len() as u64); + slow_store.update_oneshot(digest, Bytes::from(root)).await?; + Ok((digest, expected)) +} + +/// Asserts the materialized tree at `dest` matches `expected` byte-for-byte +/// (content, executable bits on unix, and symlink targets). +async fn verify_tree(dest: &Path, expected: &ExpectedTree) { + for (rel, (content, is_executable)) in &expected.files { + let path = dest.join(rel); + let actual = tokio::fs::read(&path) + .await + .unwrap_or_else(|e| panic!("missing file {}: {e}", path.display())); + assert_eq!(&actual, content, "content mismatch at {}", path.display()); + #[cfg(unix)] + { + if *is_executable { + use std::os::unix::fs::PermissionsExt; + let mode = tokio::fs::metadata(&path) + .await + .unwrap_or_else(|e| panic!("stat {}: {e}", path.display())) + .permissions() + .mode(); + assert_ne!(mode & 0o111, 0, "expected +x on {}", path.display()); + } + } + #[cfg(not(unix))] + let _ = is_executable; + } + for (rel, target) in &expected.symlinks { + let path = dest.join(rel); + let actual = tokio::fs::read_link(&path) + .await + .unwrap_or_else(|e| panic!("missing symlink {}: {e}", path.display())); + assert_eq!( + actual.to_str(), + Some(target.as_str()), + "symlink target mismatch at {}", + path.display() + ); + } +} + +/// Churn reuse: with `experimental_subtree_caching` enabled, constructing a +/// tree that differs from an already-cached tree by ONE file must reuse +/// every unchanged subtree via per-subtree hardlink hits, reconstructing +/// only the changed leaf and its ancestor mid directory. +#[nativelink_test] +async fn subtree_caching_reuses_unchanged_subtrees_on_churn() -> Result<(), Error> { + const MID_DIRS: u32 = 4; + const LEAF_DIRS: u32 = 3; + const FILES_PER_LEAF: u32 = 5; + + let memory_store = MemoryStore::new(&MemorySpec::default()); + let (root_base, expected_base) = + seed_stress_tree(&memory_store, 0, MID_DIRS, LEAF_DIRS, FILES_PER_LEAF, false).await?; + let (root_mutant, expected_mutant) = + seed_stress_tree(&memory_store, 0, MID_DIRS, LEAF_DIRS, FILES_PER_LEAF, true).await?; + assert_ne!( + root_base, root_mutant, + "mutation must change the root digest" + ); + + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + experimental_subtree_caching: true, + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + // Cold construction of the base tree: every subtree is a miss. + let base_dest = working_directory.join("base"); + assert!(!cache.get_or_create(root_base, &base_dest).await?); + verify_tree(&base_dest, &expected_base).await; + let cold_stats = cache.stats().await; + assert_eq!( + cold_stats.subtree_hits, 0, + "no subtree can hit on a cold cache" + ); + assert_eq!( + cold_stats.subtree_misses, + u64::from(MID_DIRS * LEAF_DIRS + MID_DIRS), + "every leaf and mid directory must be constructed exactly once" + ); + + // One-file-changed tree: only the changed leaf and its parent mid are + // constructed; every other subtree hardlinks from the cache. Hits are + // counted per hardlinked subtree ROOT: an unchanged mid is a single hit + // that covers all of its leaves, so the expected count is + // (unchanged mids) + (unchanged leaves inside the changed mid). + let mutant_dest = working_directory.join("mutant"); + assert!(!cache.get_or_create(root_mutant, &mutant_dest).await?); + verify_tree(&mutant_dest, &expected_mutant).await; + let churn_stats = cache.stats().await; + assert_eq!( + churn_stats.subtree_hits - cold_stats.subtree_hits, + u64::from((MID_DIRS - 1) + (LEAF_DIRS - 1)), + "all unchanged subtrees must be cache hits" + ); + assert_eq!( + churn_stats.subtree_misses - cold_stats.subtree_misses, + 2, + "only the changed leaf and the changed mid may be constructed" + ); + + // The changed file's bytes must be the mutant content, not the base's. + assert_eq!( + tokio::fs::read(mutant_dest.join("mid_0/leaf_0/file_1")).await?, + b"MUTATED-".repeat(60), + "changed file must have the mutated content" + ); + Ok(()) +} + +/// Regression guard for the default: with `experimental_subtree_caching` +/// left off, the same base-then-mutant sequence must never touch the subtree +/// cache — the counters stay zero, only root entries exist, and the results +/// are still byte-correct. +#[nativelink_test] +async fn subtree_caching_disabled_by_default() -> Result<(), Error> { + const MID_DIRS: u32 = 4; + const LEAF_DIRS: u32 = 3; + const FILES_PER_LEAF: u32 = 5; + + let memory_store = MemoryStore::new(&MemorySpec::default()); + let (root_base, expected_base) = + seed_stress_tree(&memory_store, 0, MID_DIRS, LEAF_DIRS, FILES_PER_LEAF, false).await?; + let (root_mutant, expected_mutant) = + seed_stress_tree(&memory_store, 0, MID_DIRS, LEAF_DIRS, FILES_PER_LEAF, true).await?; + + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + let base_dest = working_directory.join("base"); + assert!(!cache.get_or_create(root_base, &base_dest).await?); + verify_tree(&base_dest, &expected_base).await; + + let mutant_dest = working_directory.join("mutant"); + assert!(!cache.get_or_create(root_mutant, &mutant_dest).await?); + verify_tree(&mutant_dest, &expected_mutant).await; + + let stats = cache.stats().await; + assert_eq!(stats.subtree_hits, 0, "flag off: no subtree cache lookups"); + assert_eq!( + stats.subtree_misses, 0, + "flag off: no subtree cache constructions" + ); + assert_eq!(stats.entries, 2, "flag off: only the two roots are cached"); + Ok(()) +} + +/// Cross-root sharing: two DIFFERENT roots containing a byte-identical +/// subtree (same `Directory` digest, even under different names) must share +/// one cached subtree entry — the second root's construction gets a subtree +/// hit instead of rebuilding it. +#[nativelink_test] +async fn subtree_caching_shares_subtree_across_roots() -> Result<(), Error> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let shared_content = b"cross-root shared file".to_vec(); + let file_digest = DigestInfo::new([0x31u8; 32], shared_content.len() as u64); + memory_store + .update_oneshot(file_digest, Bytes::from(shared_content.clone())) + .await?; + let shared_dir = ProtoDirectory { + files: vec![FileNode { + name: "data.txt".to_string(), + digest: Some(file_digest.into()), + is_executable: false, + node_properties: None, + }], + directories: vec![], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let shared_dir_digest = DigestInfo::new([0x32u8; 32], shared_dir.len() as u64); + memory_store + .update_oneshot(shared_dir_digest, Bytes::from(shared_dir)) + .await?; + + let extra_content = b"only in the second root".to_vec(); + let extra_digest = DigestInfo::new([0x33u8; 32], extra_content.len() as u64); + memory_store + .update_oneshot(extra_digest, Bytes::from(extra_content.clone())) + .await?; + + // The subtree name lives in the parent's DirectoryNode, not in the + // subtree itself, so the two roots may even use different names. + let root_one = ProtoDirectory { + files: vec![], + directories: vec![DirectoryNode { + name: "sub".to_string(), + digest: Some(shared_dir_digest.into()), + }], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let root_one_digest = DigestInfo::new([0x34u8; 32], root_one.len() as u64); + memory_store + .update_oneshot(root_one_digest, Bytes::from(root_one)) + .await?; + let root_two = ProtoDirectory { + files: vec![FileNode { + name: "extra.txt".to_string(), + digest: Some(extra_digest.into()), + is_executable: false, + node_properties: None, + }], + directories: vec![DirectoryNode { + name: "renamed_sub".to_string(), + digest: Some(shared_dir_digest.into()), + }], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let root_two_digest = DigestInfo::new([0x35u8; 32], root_two.len() as u64); + memory_store + .update_oneshot(root_two_digest, Bytes::from(root_two)) + .await?; + + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + experimental_subtree_caching: true, + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + let dest_one = working_directory.join("root_one"); + assert!(!cache.get_or_create(root_one_digest, &dest_one).await?); + let stats = cache.stats().await; + assert_eq!(stats.subtree_misses, 1, "first root constructs the subtree"); + assert_eq!(stats.subtree_hits, 0); + + let dest_two = working_directory.join("root_two"); + assert!( + !cache.get_or_create(root_two_digest, &dest_two).await?, + "second root is itself a root-level miss" + ); + let stats = cache.stats().await; + assert_eq!( + stats.subtree_hits, 1, + "second root must reuse the identical subtree from the first root" + ); + assert_eq!(stats.subtree_misses, 1, "the subtree is never rebuilt"); + assert_eq!( + stats.entries, 3, + "two roots plus one shared subtree are cached" + ); + + // Both materializations are byte-correct. + assert_eq!( + tokio::fs::read(dest_one.join("sub").join("data.txt")).await?, + shared_content + ); + assert_eq!( + tokio::fs::read(dest_two.join("renamed_sub").join("data.txt")).await?, + shared_content + ); + assert_eq!( + tokio::fs::read(dest_two.join("extra.txt")).await?, + extra_content + ); + Ok(()) +} + +/// Eviction safety: with `experimental_subtree_caching` enabled and +/// `max_entries` far below what a single tree needs, several trees +/// constructed concurrently must all materialize byte-correct results with +/// no errors — eviction may never delete an entry that a construction still +/// holds a `ref_count` pin on. +#[nativelink_test(flavor = "multi_thread", worker_threads = 4)] +async fn subtree_caching_eviction_safety_under_concurrency() -> Result<(), Error> { + const NUM_TREES: u32 = 4; + + let memory_store = MemoryStore::new(&MemorySpec::default()); + let mut trees = Vec::new(); + for tree_id in 1..=NUM_TREES { + trees.push(seed_stress_tree(&memory_store, tree_id, 2, 2, 4, false).await?); + } + + let cache = Arc::new( + DirectoryCache::new( + DirectoryCacheConfig { + // Far below the 7 entries (1 root + 2 mids + 4 leaves) a + // single tree wants, so eviction races construction. + max_entries: 3, + cache_root: make_temp_path("directory_cache").into(), + experimental_subtree_caching: true, + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?, + ); + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + let mut handles = Vec::new(); + for (i, (root, _)) in trees.iter().enumerate() { + let cache = Arc::clone(&cache); + let root = *root; + let dest = working_directory.join(format!("tree_{i}")); + handles.push(tokio::spawn(async move { + cache.get_or_create(root, &dest).await + })); + } + for handle in handles { + handle.await.expect("construction task panicked")?; + } + for (i, (_, expected)) in trees.iter().enumerate() { + verify_tree(&working_directory.join(format!("tree_{i}")), expected).await; + } + Ok(()) +} + +/// Seeds a minimal three-level tree `root -> mid -> leaf -> a.txt` with +/// digests derived from `tag`, returning the root digest, the leaf +/// `Directory` proto digest, and the file content. +async fn seed_simple_nested( + slow_store: &Arc, + tag: u8, +) -> Result<(DigestInfo, DigestInfo, Vec), Error> { + let content = format!("nested-{tag}").into_bytes(); + let file_digest = DigestInfo::new([tag; 32], content.len() as u64); + slow_store + .update_oneshot(file_digest, Bytes::from(content.clone())) + .await?; + let leaf = ProtoDirectory { + files: vec![FileNode { + name: "a.txt".to_string(), + digest: Some(file_digest.into()), + is_executable: false, + node_properties: None, + }], + directories: vec![], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let leaf_digest = DigestInfo::new([tag + 1; 32], leaf.len() as u64); + slow_store + .update_oneshot(leaf_digest, Bytes::from(leaf)) + .await?; + let mid = ProtoDirectory { + files: vec![], + directories: vec![DirectoryNode { + name: "leaf".to_string(), + digest: Some(leaf_digest.into()), + }], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let mid_digest = DigestInfo::new([tag + 2; 32], mid.len() as u64); + slow_store + .update_oneshot(mid_digest, Bytes::from(mid)) + .await?; + let root = ProtoDirectory { + files: vec![], + directories: vec![DirectoryNode { + name: "mid".to_string(), + digest: Some(mid_digest.into()), + }], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let root_digest = DigestInfo::new([tag + 3; 32], root.len() as u64); + slow_store + .update_oneshot(root_digest, Bytes::from(root)) + .await?; + Ok((root_digest, leaf_digest, content)) +} + +/// Asserts `cache_root` holds no in-progress temp trees (`.tmp-*`) or +/// undeleted tombstones that a failed construction could have leaked. +async fn assert_no_scratch_leftovers(cache_root: &Path) { + let mut dir = tokio::fs::read_dir(cache_root) + .await + .expect("cache root must be readable"); + while let Some(entry) = dir.next_entry().await.expect("read_dir must not fail") { + let name = entry.file_name(); + let name = name.to_string_lossy(); + assert!( + !name.starts_with(".tmp-"), + "stale temp construction tree leaked: {name}" + ); + } +} + +/// `MemoryStore` wrapper that fails `get_part` for one digest a fixed number +/// of times, then behaves normally — a transient slow-store failure. +#[derive(Debug)] +struct FlakyStore { + inner: Store, + fail_digest: DigestInfo, + failures_remaining: AtomicU64, +} + +impl FlakyStore { + fn new(inner: Arc, fail_digest: DigestInfo, failures: u64) -> Arc { + Arc::new(Self { + inner: Store::new(inner), + fail_digest, + failures_remaining: AtomicU64::new(failures), + }) + } +} + +impl MetricsComponent for FlakyStore { + fn publish( + &self, + _kind: MetricKind, + _field_metadata: MetricFieldData, + ) -> Result { + Ok(MetricPublishKnownKindData::Component) + } +} + +#[async_trait] +impl StoreDriver for FlakyStore { + async fn post_init(self: Arc) -> Result<(), Error> { + Ok(()) + } + + async fn has_with_results( + self: Pin<&Self>, + keys: &[StoreKey<'_>], + results: &mut [Option], + ) -> Result<(), Error> { + self.inner + .as_store_driver_pin() + .has_with_results(keys, results) + .await + } + + async fn update( + self: Pin<&Self>, + key: StoreKey<'_>, + reader: DropCloserReadHalf, + size_info: UploadSizeInfo, + ) -> Result { + self.inner + .as_store_driver_pin() + .update(key, reader, size_info) + .await + } + + async fn get_part( + self: Pin<&Self>, + key: StoreKey<'_>, + writer: &mut DropCloserWriteHalf, + offset: u64, + length: Option, + ) -> Result<(), Error> { + if let StoreKey::Digest(digest) = &key + && *digest == self.fail_digest + && self.failures_remaining.load(Ordering::SeqCst) > 0 + { + self.failures_remaining.fetch_sub(1, Ordering::SeqCst); + return Err(nativelink_error::make_err!( + Code::Internal, + "synthetic transient fetch failure" + )); + } + self.inner + .as_store_driver_pin() + .get_part(key, writer, offset, length) + .await + } + + fn inner_store(&self, _key: Option) -> &dyn StoreDriver { + self + } + + fn as_any<'a>(&'a self) -> &'a (dyn core::any::Any + Sync + Send + 'static) { + self + } + + fn as_any_arc(self: Arc) -> Arc { + self + } + + fn register_remove_callback( + self: Arc, + _callback: Arc, + ) -> Result<(), Error> { + Ok(()) + } +} + +default_health_status_indicator!(FlakyStore); + +/// Construction-failure recovery: a failed construction (transient slow-store +/// error) must leave NOTHING behind — no partial tree at the canonical +/// `cache_root/` path (which would poison every retry of that stable +/// digest with `AlreadyExists`) and no stale temp trees — and the retry must +/// succeed. +#[nativelink_test] +async fn construction_failure_does_not_poison_digest() -> Result<(), Error> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let (root_digest, leaf_digest, content) = seed_simple_nested(&memory_store, 0x50).await?; + // Fail the leaf's Directory-proto fetch exactly once. + let flaky = FlakyStore::new(memory_store, leaf_digest, 1); + + let fast_spec = FilesystemSpec { + content_path: make_temp_path("cas_content"), + temp_path: make_temp_path("cas_temp"), + eviction_policy: None, + ..Default::default() + }; + let fast_store: Arc = FilesystemStore::new(&fast_spec).await.unwrap(); + let cas_store = FastSlowStore::new( + &FastSlowSpec { + fast: StoreSpec::Filesystem(fast_spec), + slow: StoreSpec::Memory(MemorySpec::default()), + fast_direction: StoreDirection::default(), + slow_direction: StoreDirection::default(), + bypass_dedup_threshold_bytes: 0, + }, + Store::new(fast_store), + Store::new(flaky), + ); + + let cache_root = PathBuf::from(make_temp_path("directory_cache")); + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: cache_root.clone(), + experimental_subtree_caching: true, + ..Default::default() + }, + cas_store, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + let result = cache + .get_or_create(root_digest, &working_directory.join("first")) + .await; + assert!(result.is_err(), "first construction must fail"); + assert_no_scratch_leftovers(&cache_root).await; + + // Retry: no AlreadyExists poisoning from the failed attempt. + let hit = cache + .get_or_create(root_digest, &working_directory.join("second")) + .await?; + assert!( + !hit, + "retry is a plain miss that must construct successfully" + ); + assert_eq!( + tokio::fs::read(working_directory.join("second/mid/leaf/a.txt")).await?, + content + ); + assert_no_scratch_leftovers(&cache_root).await; + Ok(()) +} + +/// Pin-leak / cancellation safety: a construction error makes +/// `buffer_unordered` drop sibling node futures mid-flight. The RAII +/// `EntryPin` guards must release their refcounts on drop, so no entry is +/// left permanently pinned (unevictable) and the cache stays fully usable. +#[nativelink_test(flavor = "multi_thread", worker_threads = 4)] +async fn cancelled_sibling_constructions_leak_no_pins() -> Result<(), Error> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let (root_x, leaf_x, content) = seed_simple_nested(&memory_store, 0x41).await?; + + // Tree Y reuses X's leaf and adds a subtree whose Directory proto is + // deliberately absent from the CAS, so constructing Y always fails and + // cancels the sibling (leaf) future mid-flight. + let missing_digest = DigestInfo::new([0x66u8; 32], 4); + let mid_y = ProtoDirectory { + files: vec![], + directories: vec![ + DirectoryNode { + name: "leaf".to_string(), + digest: Some(leaf_x.into()), + }, + DirectoryNode { + name: "missing".to_string(), + digest: Some(missing_digest.into()), + }, + ], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let mid_y_digest = DigestInfo::new([0x67u8; 32], mid_y.len() as u64); + memory_store + .update_oneshot(mid_y_digest, Bytes::from(mid_y)) + .await?; + let root_y = ProtoDirectory { + files: vec![], + directories: vec![DirectoryNode { + name: "mid".to_string(), + digest: Some(mid_y_digest.into()), + }], + symlinks: vec![], + node_properties: None, + } + .encode_to_vec(); + let root_y_digest = DigestInfo::new([0x68u8; 32], root_y.len() as u64); + memory_store + .update_oneshot(root_y_digest, Bytes::from(root_y)) + .await?; + + let cache = DirectoryCache::new( + DirectoryCacheConfig { + // Small budget so leaked pins would visibly block eviction. + max_entries: 2, + cache_root: make_temp_path("directory_cache").into(), + experimental_subtree_caching: true, + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + // Warm X so Y's shared leaf is (likely) served as a cache hit whose + // hardlink is what gets cancelled. + assert!( + !cache + .get_or_create(root_x, &working_directory.join("x")) + .await? + ); + assert_eq!( + tokio::fs::read(working_directory.join("x/mid/leaf/a.txt")).await?, + content + ); + + for i in 0..3 { + let result = cache + .get_or_create(root_y_digest, &working_directory.join(format!("y{i}"))) + .await; + assert!(result.is_err(), "tree Y must fail to construct"); + } + let stats = cache.stats().await; + assert_eq!( + stats.in_use_entries, 0, + "cancelled/failed constructions must drain every refcount pin" + ); + + // Everything must still be evictable and the cache fully usable. + let dest = working_directory.join("x_again"); + cache.get_or_create(root_x, &dest).await?; + assert_eq!(tokio::fs::read(dest.join("mid/leaf/a.txt")).await?, content); + let stats = cache.stats().await; + assert_eq!( + stats.in_use_entries, 0, + "no pins may remain after completion" + ); + assert!( + stats.entries <= 2, + "eviction must be able to keep the cache within max_entries" + ); + Ok(()) +} + +/// Damaged-entry recovery: a cache entry whose on-disk tree was deleted out +/// from under the map (manual cleanup, disk tooling) must not fail its +/// digest forever. The hit path invalidates the dead entry, rebuilds it, and +/// returns byte-correct results; the rebuilt entry then serves normal hits. +/// Unix-only: the damage step deletes trees containing read-only files. +#[cfg(unix)] +#[nativelink_test] +async fn damaged_cache_entry_recovers() -> Result<(), Error> { + let memory_store = MemoryStore::new(&MemorySpec::default()); + let (root_digest, _leaf_digest, content) = seed_simple_nested(&memory_store, 0x21).await?; + let cache_root = PathBuf::from(make_temp_path("directory_cache")); + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: cache_root.clone(), + experimental_subtree_caching: true, + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + assert!( + !cache + .get_or_create(root_digest, &working_directory.join("before")) + .await? + ); + + // Damage: delete every entry tree on disk while the map still holds it. + let mut dir = tokio::fs::read_dir(&cache_root).await?; + while let Some(entry) = dir.next_entry().await? { + tokio::fs::remove_dir_all(entry.path()).await?; + } + + // Recovery: the hit path fails to hardlink, invalidates the dead + // entries, and rebuilds them. Result must be byte-correct. + cache + .get_or_create(root_digest, &working_directory.join("after")) + .await?; + assert_eq!( + tokio::fs::read(working_directory.join("after/mid/leaf/a.txt")).await?, + content + ); + + // The rebuilt entry serves the next request as a normal hit. + let hit = cache + .get_or_create(root_digest, &working_directory.join("again")) + .await?; + assert!(hit, "rebuilt entry must serve as a cache hit"); + assert_eq!( + tokio::fs::read(working_directory.join("again/mid/leaf/a.txt")).await?, + content + ); + Ok(()) +} + +/// Size accounting (flag on): an entry's recorded size covers only bytes not +/// owned by a descendant entry, so the cache's size total equals the tree's +/// unique byte total — not a depth-multiplied figure that would inflate +/// `max_size_bytes` pressure and self-defeat the cache via phantom +/// evictions. +#[nativelink_test] +async fn subtree_caching_size_accounting_not_depth_multiplied() -> Result<(), Error> { + const MID_DIRS: u32 = 3; + const LEAF_DIRS: u32 = 2; + const FILES_PER_LEAF: u32 = 4; + + let memory_store = MemoryStore::new(&MemorySpec::default()); + let (root_digest, expected) = + seed_stress_tree(&memory_store, 0, MID_DIRS, LEAF_DIRS, FILES_PER_LEAF, false).await?; + let unique_bytes: u64 = expected + .files + .values() + .map(|(content, _)| content.len() as u64) + .sum(); + + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + experimental_subtree_caching: true, + ..Default::default() + }, + make_cas_store(memory_store).await, + ) + .await?; + let working_directory = PathBuf::from(make_temp_path("working_directory")); + tokio::fs::create_dir_all(&working_directory).await?; + + assert!( + !cache + .get_or_create(root_digest, &working_directory.join("tree")) + .await? + ); + verify_tree(&working_directory.join("tree"), &expected).await; + + let stats = cache.stats().await; + assert_eq!( + stats.total_size_bytes, unique_bytes, + "cache size total must equal the tree's unique bytes" + ); + assert_eq!( + stats.entries, + (MID_DIRS * LEAF_DIRS + MID_DIRS + 1) as usize, + "every subtree plus the root must have its own entry" + ); + Ok(()) +} + +#[derive(Clone)] +struct PaginatedGetTreeServer { + root: ProtoDirectory, + child: ProtoDirectory, + requests: Arc>>, +} + +type PaginatedGetTreeStream = + Pin> + Send + 'static>>; + +#[async_trait] +impl ContentAddressableStorage for PaginatedGetTreeServer { + type GetTreeStream = PaginatedGetTreeStream; + + async fn find_missing_blobs( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test")) + } + + async fn batch_update_blobs( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test")) + } + + async fn batch_read_blobs( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test")) + } + + async fn get_tree( + &self, + request: Request, + ) -> Result, Status> { + const SECOND_PAGE_TOKEN: &str = "child-directory-page"; + + let request = request.into_inner(); + self.requests.lock().await.push(request.clone()); + let response = match request.page_token.as_str() { + "" => GetTreeResponse { + directories: vec![self.root.clone()], + next_page_token: SECOND_PAGE_TOKEN.to_string(), + }, + SECOND_PAGE_TOKEN => GetTreeResponse { + directories: vec![self.child.clone()], + next_page_token: String::new(), + }, + token => { + return Err(Status::invalid_argument(format!( + "unexpected token: {token}" + ))); + } + }; + Ok(Response::new(Box::pin(futures::stream::iter([Ok( + response, + )])))) + } + + async fn split_blob( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test")) + } + + async fn splice_blob( + &self, + _request: Request, + ) -> Result, Status> { + Err(Status::unimplemented("not used by this test")) + } +} + +fn proto_digest(directory: &ProtoDirectory) -> DigestInfo { + let mut hasher = default_digest_hasher_func().hasher(); + hasher.update(&directory.encode_to_vec()); + hasher.finalize_digest() +} + +/// The [REAPI request contract] says a zero page size does not require a +/// server to return the entire tree in one response, and the [REAPI response +/// contract] tells the client to continue with `next_page_token`. This test +/// therefore deliberately uses the smallest tree that cannot be represented +/// by the first page alone. The first page contains only the root `Directory`, +/// whose `DirectoryNode` names and hashes the child, while the second page +/// contains only that child `Directory`. +/// +/// Using two different, content-derived directory digests matters here: the +/// public `get_or_create` operation cannot materialize the named child unless +/// the prefetch map contains both pages. The fake server also records the +/// requests so the test verifies that the continuation token was copied +/// exactly into the follow-up request and that fetching stopped as soon as the +/// server returned an empty token. No directory protos are seeded into the +/// filesystem store, and the server intentionally does not expose a +/// `ByteStream` service. Consequently, ignoring the second page cannot be +/// hidden by the normal per-level fallback: that fallback would fail while +/// fetching the absent child proto. Before the fix, the client drained the first response +/// stream, discarded the advertised child-directory page, and took precisely +/// that failing fallback path. +/// +/// [REAPI request contract]: https://github.com/bazelbuild/remote-apis/blob/becdd8f9ff811df88a22d3eadd6341753d51d167/build/bazel/remote/execution/v2/remote_execution.proto#L1932-L1942 +/// [REAPI response contract]: https://github.com/bazelbuild/remote-apis/blob/becdd8f9ff811df88a22d3eadd6341753d51d167/build/bazel/remote/execution/v2/remote_execution.proto#L1961-L1965 +#[nativelink_test] +async fn get_tree_prefetch_follows_server_pagination() -> Result<(), Error> { + let child = ProtoDirectory::default(); + let child_digest = proto_digest(&child); + let root = ProtoDirectory { + directories: vec![DirectoryNode { + name: "second-page".to_string(), + digest: Some(child_digest.into()), + }], + ..Default::default() + }; + let root_digest = proto_digest(&root); + let requests = Arc::new(Mutex::new(Vec::new())); + let service = PaginatedGetTreeServer { + root, + child, + requests: Arc::clone(&requests), + }; + let listener = TcpIncoming::bind("127.0.0.1:0".parse().unwrap()).unwrap(); + let port = listener.local_addr().unwrap().port(); + background_spawn!("paginated_get_tree_server", async move { + Server::builder() + .add_service(ContentAddressableStorageServer::new(service)) + .serve_with_incoming(listener) + .await + .unwrap(); + }); + + let grpc_spec = GrpcSpec { + instance_name: String::new(), + endpoints: vec![GrpcEndpoint { + address: format!("http://127.0.0.1:{port}"), + tls_config: None, + concurrency_limit: None, + connect_timeout_s: 0, + tcp_keepalive_s: 0, + http2_keepalive_interval_s: 0, + http2_keepalive_timeout_s: 0, + }], + store_type: StoreType::Cas, + retry: Retry::default(), + max_concurrent_requests: 0, + connections_per_endpoint: 0, + rpc_timeout_s: 1, + use_legacy_resource_names: false, + headers: HashMap::new(), + forward_headers: vec![], + experimental_read_batching: None, + experimental_remote_cache_compression: Some(false), + }; + let fast_spec = FilesystemSpec { + content_path: make_temp_path("paginated_get_tree_cas_content"), + temp_path: make_temp_path("paginated_get_tree_cas_temp"), + ..Default::default() + }; + let fast_store: Arc = FilesystemStore::new(&fast_spec).await?; + let grpc_store = GrpcStore::new(&grpc_spec).await?; + let cas_store = FastSlowStore::new( + &FastSlowSpec { + fast: StoreSpec::Filesystem(fast_spec), + slow: StoreSpec::Grpc(grpc_spec), + fast_direction: StoreDirection::default(), + slow_direction: StoreDirection::default(), + bypass_dedup_threshold_bytes: 0, + }, + Store::new(fast_store), + Store::new(grpc_store), + ); + let cache = DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("paginated_get_tree_directory_cache").into(), + experimental_get_tree_prefetch: true, + ..Default::default() + }, + cas_store, + ) + .await?; + + let destination = PathBuf::from(make_temp_path("paginated_get_tree_destination")); + assert!(!cache.get_or_create(root_digest, &destination).await?); + assert!(destination.join("second-page").is_dir()); + + let requests = requests.lock().await; + assert_eq!(requests.len(), 2); + assert_eq!(requests[0].page_token, ""); + assert_eq!(requests[1].page_token, "child-directory-page"); + assert_eq!(requests[0].root_digest, Some(root_digest.into())); + assert_eq!(requests[1].root_digest, Some(root_digest.into())); + + Ok(()) +} diff --git a/nativelink-worker/tests/local_worker_test.rs b/nativelink-worker/tests/local_worker_test.rs index bc72a3882..a359dfcc2 100644 --- a/nativelink-worker/tests/local_worker_test.rs +++ b/nativelink-worker/tests/local_worker_test.rs @@ -193,6 +193,84 @@ async fn kill_all_called_on_disconnect() -> Result<(), Error> { Ok(()) } +/// A disconnect that catches an action mid-handoff must still reconnect. +/// Returning from the worker's main loop here aborts the process, so a +/// scheduler blip that happened to land while an action was in transit took +/// the whole worker down and every action it held had to run again elsewhere. +#[nativelink_test] +async fn reconnects_when_action_stuck_in_transit_on_disconnect() -> Result<(), Error> { + let mut test_context = setup_local_worker(HashMap::new()).await; + let streaming_response = test_context.maybe_streaming_response.take().unwrap(); + + test_context + .client + .expect_connect_worker(Ok(streaming_response)) + .await; + + let expected_worker_id = "foobar".to_string(); + let tx_stream = test_context.maybe_tx_stream.take().unwrap(); + tx_stream + .send(Frame::data( + encode_stream_proto(&UpdateForWorker { + update: Some(Update::ConnectionResult(ConnectionResult { + worker_id: expected_worker_id.clone(), + })), + }) + .unwrap(), + )) + .await + .map_err(|e| make_input_err!("Could not send : {:?}", e))?; + + let action_info = ActionInfo { + command_digest: DigestInfo::new([1u8; 32], 10), + input_root_digest: DigestInfo::new([2u8; 32], 10), + timeout: Duration::from_secs(1), + platform_properties: HashMap::new(), + priority: 0, + load_timestamp: SystemTime::UNIX_EPOCH, + insert_timestamp: SystemTime::UNIX_EPOCH, + unique_qualifier: ActionUniqueQualifier::Uncacheable(ActionUniqueKey { + instance_name: INSTANCE_NAME.to_string(), + digest_function: DigestHasherFunc::Sha256, + digest: DigestInfo::new([3u8; 32], 10), + }), + }; + + // Start an action, but deliberately never answer create_and_add_action. + // The action stays counted as in transit, so the drain wait on disconnect + // runs to its limit instead of settling. + tx_stream + .send(Frame::data( + encode_stream_proto(&UpdateForWorker { + update: Some(Update::StartAction(StartExecute { + execute_request: Some((&action_info).into()), + operation_id: String::new(), + queued_timestamp: None, + platform: Some(Platform::default()), + worker_id: expected_worker_id, + })), + }) + .unwrap(), + )) + .await + .map_err(|e| make_input_err!("Could not send : {:?}", e))?; + + // Disconnect while that action is still in transit. + drop(tx_stream); + + test_context.actions_manager.expect_kill_all().await; + + // The worker must come back rather than exiting. + let (_, streaming_response) = setup_grpc_stream(); + let props = test_context + .client + .expect_connect_worker(Ok(streaming_response)) + .await; + assert_eq!(props, ConnectWorkerRequest::default()); + + Ok(()) +} + #[nativelink_test] async fn blake3_digest_function_registered_properly() -> Result<(), Error> { let mut test_context = setup_local_worker(HashMap::new()).await; diff --git a/nativelink-worker/tests/running_actions_manager_test.rs b/nativelink-worker/tests/running_actions_manager_test.rs index 8768af642..6a25b92f7 100644 --- a/nativelink-worker/tests/running_actions_manager_test.rs +++ b/nativelink-worker/tests/running_actions_manager_test.rs @@ -37,7 +37,7 @@ mod tests { EnvironmentSource, UploadActionResultConfig, UploadCacheResultsStrategy, }; use nativelink_config::stores::{ - FastSlowSpec, FilesystemSpec, MemorySpec, StoreDirection, StoreSpec, + EvictionPolicy, FastSlowSpec, FilesystemSpec, MemorySpec, StoreDirection, StoreSpec, }; use nativelink_error::{Code, Error, ResultExt, make_input_err}; use nativelink_macro::nativelink_test; @@ -67,7 +67,8 @@ mod tests { }; use nativelink_util::common::{DigestInfo, fs, make_temp_path}; use nativelink_util::digest_hasher::{DigestHasher, DigestHasherFunc}; - use nativelink_util::store_trait::{Store, StoreLike}; + use nativelink_util::store_trait::{Store, StoreKey, StoreLike}; + use nativelink_worker::directory_cache::{DirectoryCache, DirectoryCacheConfig}; #[cfg(target_os = "linux")] use nativelink_worker::namespace_utils; use nativelink_worker::running_actions_manager::{ @@ -102,11 +103,25 @@ mod tests { Arc, ), Error, + > { + setup_stores_with_eviction_policy(None).await + } + + async fn setup_stores_with_eviction_policy( + eviction_policy: Option, + ) -> Result< + ( + Arc, + Arc, + Arc, + Arc, + ), + Error, > { let fast_config = FilesystemSpec { content_path: make_temp_path("content_path"), temp_path: make_temp_path("temp_path"), - eviction_policy: None, + eviction_policy, ..Default::default() }; let slow_config = MemorySpec::default(); @@ -258,6 +273,288 @@ mod tests { Ok(()) } + #[nativelink_test] + async fn active_action_input_lease_survives_fast_store_pressure() + -> Result<(), Box> { + const FILE_CONTENT: &[u8] = b"leased input"; + const PRESSURE_CONTENT: &[u8] = b"pressure"; + + let (fast_store, slow_store, cas_store, _ac_store) = + setup_stores_with_eviction_policy(Some(EvictionPolicy { + max_count: 1, + ..Default::default() + })) + .await?; + + let file_digest = DigestInfo::new([7u8; 32], FILE_CONTENT.len() as u64); + slow_store + .as_ref() + .update_oneshot(file_digest, FILE_CONTENT.into()) + .await?; + let input_root_digest = serialize_and_upload_message( + &Directory { + files: vec![FileNode { + name: "input.txt".to_string(), + digest: Some(file_digest.into()), + ..Default::default() + }], + ..Default::default() + }, + slow_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let command_digest = serialize_and_upload_message( + &Command::default(), + slow_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let action_digest = serialize_and_upload_message( + &Action { + command_digest: Some(command_digest.into()), + input_root_digest: Some(input_root_digest.into()), + ..Default::default() + }, + slow_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let operation_id = OperationId::default().to_string(); + + let root_action_directory = make_temp_path("root_action_directory"); + fs::create_dir_all(&root_action_directory).await?; + let directory_cache = Arc::new( + DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + ..Default::default() + }, + cas_store.clone(), + ) + .await?, + ); + let running_actions_manager = + Arc::new(RunningActionsManagerImpl::new(RunningActionsManagerArgs { + root_action_directory, + execution_configuration: ExecutionConfiguration::default(), + cas_store: cas_store.clone(), + ac_store: None, + historical_store: Store::new(cas_store.clone()), + upload_action_result_config: &UploadActionResultConfig { + upload_ac_results_strategy: UploadCacheResultsStrategy::Never, + ..Default::default() + }, + max_action_timeout: Duration::from_mins(10), + max_upload_timeout: Duration::from_secs(DEFAULT_MAX_UPLOAD_TIMEOUT), + max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), + max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), + timeout_handled_externally: false, + active_input_leases: true, + directory_cache: Some(directory_cache), + #[cfg(target_os = "linux")] + use_namespaces: use_namespaces(), + })?); + + let action = running_actions_manager + .create_and_add_action( + "test-worker".to_string(), + StartExecute { + execute_request: Some(ExecuteRequest { + action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), + ..Default::default() + }), + operation_id: operation_id.clone(), + ..Default::default() + }, + ) + .await? + .prepare_action() + .await?; + + let pressure_digest = DigestInfo::new([8u8; 32], PRESSURE_CONTENT.len() as u64); + fast_store + .as_ref() + .update_oneshot(pressure_digest, PRESSURE_CONTENT.into()) + .await?; + assert!( + fast_store + .as_ref() + .has(StoreKey::Digest(file_digest)) + .await? + .is_some(), + "an active action input must survive fast-tier pressure", + ); + + let duplicate_result = running_actions_manager + .create_and_add_action( + "test-worker".to_string(), + StartExecute { + execute_request: Some(ExecuteRequest { + action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), + ..Default::default() + }), + operation_id, + ..Default::default() + }, + ) + .await; + let duplicate_error = + duplicate_result.expect_err("a duplicate operation id must be rejected"); + assert_eq!(duplicate_error.code, Code::AlreadyExists); + assert!( + fs::metadata(action.get_work_directory()).await.is_ok(), + "a duplicate operation must not remove the active action directory", + ); + + let action = action.cleanup().await?; + let second_pressure_digest = DigestInfo::new([9u8; 32], PRESSURE_CONTENT.len() as u64); + fast_store + .as_ref() + .update_oneshot(second_pressure_digest, PRESSURE_CONTENT.into()) + .await?; + assert_eq!( + fast_store + .as_ref() + .has(StoreKey::Digest(file_digest)) + .await?, + None, + "released action inputs must become ordinary eviction candidates", + ); + + drop(action); + Ok(()) + } + + #[nativelink_test] + async fn action_inputs_stay_evictable_when_leases_disabled() + -> Result<(), Box> { + const FILE_CONTENT: &[u8] = b"unleased input"; + const PRESSURE_CONTENT: &[u8] = b"pressure"; + // High enough that action preparation never triggers eviction; the + // pressure loop below inserts this many fresh digests so every entry + // that predates it is evicted. + const MAX_COUNT: u64 = 10; + + let (fast_store, slow_store, cas_store, _ac_store) = + setup_stores_with_eviction_policy(Some(EvictionPolicy { + max_count: MAX_COUNT, + ..Default::default() + })) + .await?; + + let file_digest = DigestInfo::new([7u8; 32], FILE_CONTENT.len() as u64); + slow_store + .as_ref() + .update_oneshot(file_digest, FILE_CONTENT.into()) + .await?; + let input_root_digest = serialize_and_upload_message( + &Directory { + files: vec![FileNode { + name: "input.txt".to_string(), + digest: Some(file_digest.into()), + ..Default::default() + }], + ..Default::default() + }, + slow_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let command_digest = serialize_and_upload_message( + &Command::default(), + slow_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let action_digest = serialize_and_upload_message( + &Action { + command_digest: Some(command_digest.into()), + input_root_digest: Some(input_root_digest.into()), + ..Default::default() + }, + slow_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + + let root_action_directory = make_temp_path("root_action_directory"); + fs::create_dir_all(&root_action_directory).await?; + let directory_cache = Arc::new( + DirectoryCache::new( + DirectoryCacheConfig { + cache_root: make_temp_path("directory_cache").into(), + ..Default::default() + }, + cas_store.clone(), + ) + .await?, + ); + let running_actions_manager = + Arc::new(RunningActionsManagerImpl::new(RunningActionsManagerArgs { + root_action_directory, + execution_configuration: ExecutionConfiguration::default(), + cas_store: cas_store.clone(), + ac_store: None, + historical_store: Store::new(cas_store.clone()), + upload_action_result_config: &UploadActionResultConfig { + upload_ac_results_strategy: UploadCacheResultsStrategy::Never, + ..Default::default() + }, + max_action_timeout: Duration::from_mins(10), + max_upload_timeout: Duration::from_secs(DEFAULT_MAX_UPLOAD_TIMEOUT), + max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), + max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), + timeout_handled_externally: false, + active_input_leases: false, + directory_cache: Some(directory_cache), + #[cfg(target_os = "linux")] + use_namespaces: use_namespaces(), + })?); + + let action = running_actions_manager + .create_and_add_action( + "test-worker".to_string(), + StartExecute { + execute_request: Some(ExecuteRequest { + action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), + ..Default::default() + }), + operation_id: OperationId::default().to_string(), + ..Default::default() + }, + ) + .await? + .prepare_action() + .await?; + + for pressure_index in 0..MAX_COUNT { + let pressure_digest = DigestInfo::new( + [0x80 + u8::try_from(pressure_index)?; 32], + PRESSURE_CONTENT.len() as u64, + ); + fast_store + .as_ref() + .update_oneshot(pressure_digest, PRESSURE_CONTENT.into()) + .await?; + } + assert_eq!( + fast_store + .as_ref() + .has(StoreKey::Digest(file_digest)) + .await?, + None, + "with active input leases disabled, the fast tier must honor its eviction limits even while an action is running", + ); + + let action = action.cleanup().await?; + drop(action); + Ok(()) + } + #[nativelink_test] async fn download_to_directory_folder_download_test() -> Result<(), Box> { @@ -586,6 +883,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -645,6 +943,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -712,6 +1011,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -773,6 +1073,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -840,6 +1141,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1024,6 +1326,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1100,6 +1403,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -1209,6 +1513,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1280,6 +1585,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -1463,6 +1769,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1514,6 +1821,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -1562,7 +1870,7 @@ mod tests { b"hello-from-outside".len() ); // Verify the blob actually landed in CAS by re-reading it. - let key: nativelink_util::store_trait::StoreKey<'_> = uploaded.digest.into(); + let key: StoreKey<'_> = uploaded.digest.into(); let blob = slow_store.as_ref().get_part_unchunked(key, 0, None).await?; assert_eq!(blob.as_ref(), b"hello-from-outside"); Ok(()) @@ -1615,6 +1923,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1665,6 +1974,7 @@ mod tests { .await?; let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -1723,7 +2033,7 @@ mod tests { .clone() .expect("inner.txt must have a digest") .try_into()?; - let key: nativelink_util::store_trait::StoreKey<'_> = inner_digest.into(); + let key: StoreKey<'_> = inner_digest.into(); let blob = slow_store.as_ref().get_part_unchunked(key, 0, None).await?; assert_eq!(blob.as_ref(), b"inner-payload"); Ok(()) @@ -1758,6 +2068,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1811,6 +2122,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -1896,6 +2208,7 @@ mod tests { max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -1962,6 +2275,7 @@ mod tests { let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -2102,6 +2416,7 @@ exit 0 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2145,6 +2460,7 @@ exit 0 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -2281,6 +2597,7 @@ exit 0 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2320,7 +2637,7 @@ exit 0 }], }), timeout: Some(prost_types::Duration { - seconds: TASK_TIMEOUT.as_secs() as i64, + seconds: TASK_TIMEOUT.as_secs().try_into().unwrap_or(i64::MAX), nanos: 0, }), ..Default::default() @@ -2334,6 +2651,7 @@ exit 0 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -2454,6 +2772,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2494,6 +2813,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -2544,6 +2864,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2622,6 +2943,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2707,6 +3029,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2813,6 +3136,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2863,6 +3187,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -2934,6 +3259,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3028,7 +3354,7 @@ exit 1 command_digest: Some(command_digest.into()), input_root_digest: Some(input_root_digest.into()), timeout: Some(prost_types::Duration { - seconds: TASK_TIMEOUT.as_secs() as i64, + seconds: TASK_TIMEOUT.as_secs().try_into().unwrap_or(i64::MAX), nanos: 0, }), ..Default::default() @@ -3056,6 +3382,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3074,6 +3401,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3118,7 +3446,7 @@ exit 1 command_digest: Some(command_digest.into()), input_root_digest: Some(input_root_digest.into()), timeout: Some(prost_types::Duration { - seconds: TASK_TIMEOUT.as_secs() as i64, + seconds: TASK_TIMEOUT.as_secs().try_into().unwrap_or(i64::MAX), nanos: 0, }), ..Default::default() @@ -3146,6 +3474,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3164,6 +3493,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3208,7 +3538,7 @@ exit 1 command_digest: Some(command_digest.into()), input_root_digest: Some(input_root_digest.into()), timeout: Some(prost_types::Duration { - seconds: TASK_TIMEOUT.as_secs() as i64, + seconds: TASK_TIMEOUT.as_secs().try_into().unwrap_or(i64::MAX), nanos: 0, }), ..Default::default() @@ -3236,6 +3566,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3254,6 +3585,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3323,6 +3655,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3385,6 +3718,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3474,6 +3808,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3531,6 +3866,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3642,6 +3978,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3694,6 +4031,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3719,6 +4057,130 @@ exit 1 Ok(()) } + /// Regression for skipping the `pre_exec` hook when namespaces are off. + /// With namespaces disabled (the default) the action spawn goes through + /// `posix_spawn` instead of `fork`, and `process_group(0)` must still make + /// the child its own process-group leader (pgid == pid). + #[cfg(target_os = "linux")] + #[nativelink_test] + async fn no_namespace_action_is_process_group_leader() -> Result<(), Box> + { + const WORKER_ID: &str = "foo_worker_id"; + + fn test_monotonic_clock() -> SystemTime { + static CLOCK: AtomicU64 = AtomicU64::new(0); + monotonic_clock(&CLOCK) + } + + let (_, _, cas_store, ac_store) = setup_stores().await?; + let root_action_directory = make_temp_path("root_action_directory"); + fs::create_dir_all(&root_action_directory).await?; + + let running_actions_manager = Arc::new(RunningActionsManagerImpl::new_with_callbacks( + RunningActionsManagerArgs { + root_action_directory, + cas_store: cas_store.clone(), + ac_store: Some(Store::new(ac_store.clone())), + execution_configuration: ExecutionConfiguration::default(), + historical_store: Store::new(cas_store.clone()), + upload_action_result_config: &UploadActionResultConfig { + upload_ac_results_strategy: UploadCacheResultsStrategy::Never, + ..Default::default() + }, + max_action_timeout: Duration::MAX, + max_upload_timeout: Duration::from_secs(DEFAULT_MAX_UPLOAD_TIMEOUT), + max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), + max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), + timeout_handled_externally: false, + active_input_leases: false, + directory_cache: None, + // Pin namespaces off so this exercises the no-pre_exec/posix_spawn + // path regardless of what the host kernel supports. + use_namespaces: nativelink_worker::running_actions_manager::UseNamespaces::No, + }, + Callbacks { + now_fn: test_monotonic_clock, + sleep_fn: |_duration| Box::pin(future::pending()), + }, + )?); + + // Print the shell's own pid (field 1) and process-group id (field 5) + // from its /proc stat line; process_group(0) makes them equal. + let command = Command { + arguments: vec![ + "sh".to_string(), + "-c".to_string(), + "read -r pid _ _ _ pgrp _ < /proc/$$/stat; printf '%s %s' \"$pid\" \"$pgrp\"" + .to_string(), + ], + output_paths: vec![], + working_directory: ".".to_string(), + environment_variables: vec![EnvironmentVariable { + name: "PATH".to_string(), + value: env::var("PATH").unwrap(), + }], + ..Default::default() + }; + let command_digest = serialize_and_upload_message( + &command, + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let input_root_digest = serialize_and_upload_message( + &Directory::default(), + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let action = Action { + command_digest: Some(command_digest.into()), + input_root_digest: Some(input_root_digest.into()), + ..Default::default() + }; + let action_digest = serialize_and_upload_message( + &action, + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + + let execute_request = ExecuteRequest { + action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), + ..Default::default() + }; + let operation_id = OperationId::default().to_string(); + let running_action_impl = running_actions_manager + .create_and_add_action( + WORKER_ID.to_string(), + StartExecute { + execute_request: Some(execute_request), + operation_id, + ..Default::default() + }, + ) + .await?; + + let action_result = run_action(running_action_impl.clone()).await?; + assert_eq!( + action_result.exit_code, 0, + "action should run to completion via posix_spawn" + ); + + let stdout = cas_store + .as_ref() + .get_part_unchunked(action_result.stdout_digest, 0, None) + .await?; + let stdout = from_utf8(&stdout)?; + let (pid, pgrp) = stdout.split_once(' ').expect("expected 'pid pgrp' output"); + assert_eq!( + pid, pgrp, + "spawned process should be its own process-group leader (pid={pid} pgrp={pgrp})" + ); + Ok(()) + } + #[nativelink_test] async fn action_directory_contents_are_cleaned() -> Result<(), Box> { const WORKER_ID: &str = "foo_worker_id"; @@ -3745,6 +4207,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -3792,6 +4255,7 @@ exit 1 let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -3910,6 +4374,7 @@ exit 1 StartExecute { execute_request: Some(ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }), operation_id: operation_id.to_string(), @@ -3952,6 +4417,7 @@ exit 1 max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4051,6 +4517,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4118,6 +4585,7 @@ done let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -4234,6 +4702,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4302,6 +4771,7 @@ done let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -4357,6 +4827,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4393,6 +4864,7 @@ done let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; @@ -4501,6 +4973,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4537,6 +5010,7 @@ done let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; @@ -4612,6 +5086,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4670,6 +5145,7 @@ done StartExecute { execute_request: Some(ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }), operation_id, @@ -4754,6 +5230,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4823,6 +5300,7 @@ done StartExecute { execute_request: Some(ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }), operation_id: OperationId::default().to_string(), @@ -4927,6 +5405,7 @@ done max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), timeout_handled_externally: false, + active_input_leases: false, directory_cache: None, #[cfg(target_os = "linux")] use_namespaces: use_namespaces(), @@ -4939,6 +5418,7 @@ done let execute_request = ExecuteRequest { action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), ..Default::default() }; let operation_id = OperationId::default().to_string(); @@ -4990,6 +5470,48 @@ done ); } + #[cfg(target_os = "linux")] + #[test] + fn parse_cpu_ticks_from_stat_sums_user_and_system_time() { + use nativelink_worker::running_actions_manager::parse_cpu_ticks_from_stat; + // Fields after the final ')': state ppid pgrp session tty tpgid flags + // minflt cminflt majflt cmajflt utime stime ... + // utime = 120, stime = 34, so 154 ticks. + assert_eq!( + parse_cpu_ticks_from_stat( + "315 (perl) S 1 60 60 0 -1 0 100 0 200 0 120 34 7 9 20 0 1 0" + ), + Some(154) + ); + } + + #[cfg(target_os = "linux")] + #[test] + fn parse_cpu_ticks_from_stat_handles_comm_with_spaces_and_parens() { + use nativelink_worker::running_actions_manager::parse_cpu_ticks_from_stat; + // Same trap as the pgid parser: a `comm` containing ')' would shift + // every field if parsed from the left. + assert_eq!( + parse_cpu_ticks_from_stat( + "1234 (weird )( name) R 1 777 777 0 -1 0 1 2 3 4 11 22 0 0 0 0" + ), + Some(33) + ); + } + + #[cfg(target_os = "linux")] + #[test] + fn parse_cpu_ticks_from_stat_rejects_malformed_input() { + use nativelink_worker::running_actions_manager::parse_cpu_ticks_from_stat; + assert_eq!(parse_cpu_ticks_from_stat("no parenthesis here"), None); + // Truncated before utime. + assert_eq!( + parse_cpu_ticks_from_stat("123 (only) S 1 60 60 0 -1 0"), + None + ); + assert_eq!(parse_cpu_ticks_from_stat(""), None); + } + #[cfg(target_os = "linux")] #[test] fn parse_pgid_from_stat_rejects_malformed_input() { @@ -4998,4 +5520,156 @@ done assert_eq!(parse_pgid_from_stat("123 (only) S"), None); // too few fields assert_eq!(parse_pgid_from_stat(""), None); } + + // Regression test for #2636: deeply nested directories with a single + // semaphore permit previously deadlocked because dir_futures and + // file_futures competed for the same permit inside try_join3. + // The fix awaits dir_futures first so permits are released before + // file/symlink uploads begin. + + #[nativelink_test] + #[cfg(target_family = "unix")] + async fn upload_with_single_permit_nested_dirs() -> Result<(), Box> { + const WORKER_ID: &str = "foo_worker_id"; + + fn test_monotonic_clock() -> SystemTime { + static CLOCK: AtomicU64 = AtomicU64::new(0); + monotonic_clock(&CLOCK) + } + + let (_, _, cas_store, ac_store) = setup_stores().await?; + let root_action_directory = make_temp_path("root_action_directory"); + fs::create_dir_all(&root_action_directory).await?; + + // Take all but one FD permit away to trigger the deadlock scenario. + let _permits = stream::iter(1..fs::OPEN_FILE_SEMAPHORE.available_permits()) + .then(|_| fs::OPEN_FILE_SEMAPHORE.acquire()) + .try_collect::>() + .await?; + assert_eq!(1, fs::OPEN_FILE_SEMAPHORE.available_permits()); + + let running_actions_manager = Arc::new(RunningActionsManagerImpl::new_with_callbacks( + RunningActionsManagerArgs { + root_action_directory, + execution_configuration: ExecutionConfiguration::default(), + cas_store: cas_store.clone(), + ac_store: Some(Store::new(ac_store.clone())), + historical_store: Store::new(cas_store.clone()), + upload_action_result_config: &UploadActionResultConfig { + upload_ac_results_strategy: UploadCacheResultsStrategy::Never, + ..Default::default() + }, + max_action_timeout: Duration::MAX, + max_upload_timeout: Duration::from_secs(DEFAULT_MAX_UPLOAD_TIMEOUT), + max_cleanup_wait: Duration::from_secs(DEFAULT_MAX_CLEANUP_WAIT), + max_cleanup_backoff: Duration::from_millis(DEFAULT_MAX_CLEANUP_BACKOFF), + timeout_handled_externally: false, + active_input_leases: false, + directory_cache: None, + #[cfg(target_os = "linux")] + use_namespaces: use_namespaces(), + }, + Callbacks { + now_fn: test_monotonic_clock, + sleep_fn: |_duration| Box::pin(future::pending()), + }, + )?); + + // Create 3-level nested dirs: out/a/b/ with files at each level. + // This exercises recursive upload_directory under permit starvation. + let arguments = vec![ + "sh".to_string(), + "-c".to_string(), + concat!( + "mkdir -p ./out/a/b && ", + "printf 'root ' > ./out/root.txt && ", + "printf 'mid ' > ./out/a/mid.txt && ", + "printf 'leaf ' > ./out/a/b/leaf.txt && ", + "printf 'ok-stdout '; >&2 printf 'ok-stderr '" + ) + .to_string(), + ]; + let working_directory = "some_cwd"; + let command = Command { + arguments, + output_paths: vec!["out".to_string()], + working_directory: working_directory.to_string(), + environment_variables: vec![EnvironmentVariable { + name: "PATH".to_string(), + value: env::var("PATH").unwrap(), + }], + ..Default::default() + }; + let command_digest = serialize_and_upload_message( + &command, + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let input_root_digest = serialize_and_upload_message( + &Directory { + directories: vec![DirectoryNode { + name: working_directory.to_string(), + digest: Some( + serialize_and_upload_message( + &Directory::default(), + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await? + .into(), + ), + }], + ..Default::default() + }, + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + let action = Action { + command_digest: Some(command_digest.into()), + input_root_digest: Some(input_root_digest.into()), + ..Default::default() + }; + let action_digest = serialize_and_upload_message( + &action, + cas_store.as_pin(), + &mut DigestHasherFunc::Sha256.hasher(), + ) + .await?; + + let execute_request = ExecuteRequest { + action_digest: Some(action_digest.into()), + digest_function: ProtoDigestFunction::Sha256.into(), + ..Default::default() + }; + let operation_id = OperationId::default().to_string(); + + let running_action_impl = running_actions_manager + .create_and_add_action( + WORKER_ID.to_string(), + StartExecute { + execute_request: Some(execute_request), + operation_id, + queued_timestamp: None, + platform: action.platform.clone(), + worker_id: WORKER_ID.to_string(), + }, + ) + .await?; + + // This would deadlock before the fix in #2636 because nested + // dir_futures and file_futures would compete for the single permit. + let action_result = run_action(running_action_impl.clone()).await?; + + assert_eq!(action_result.exit_code, 0, "action should succeed"); + // Verify the nested directory tree was uploaded. + assert_eq!( + action_result.output_folders.len(), + 1, + "expected one output directory" + ); + assert_eq!(action_result.output_folders[0].path, "out"); + Ok(()) + } } diff --git a/nativelink-worker/tests/utils/local_worker_test_utils.rs b/nativelink-worker/tests/utils/local_worker_test_utils.rs index 40eb5f1b8..849432bec 100644 --- a/nativelink-worker/tests/utils/local_worker_test_utils.rs +++ b/nativelink-worker/tests/utils/local_worker_test_utils.rs @@ -37,8 +37,8 @@ use tonic::{ Streaming, codec::Codec, // Needed for .decoder(). codec::CompressionEncoding, - codec::ProstCodec, }; +use tonic_prost::ProstCodec; use tracing::debug; use super::mock_running_actions_manager::MockRunningActionsManager; diff --git a/run_integration_tests.sh b/run_integration_tests.sh index c1009a909..451cf1a27 100755 --- a/run_integration_tests.sh +++ b/run_integration_tests.sh @@ -127,7 +127,10 @@ for pattern in "${TEST_PATTERNS[@]}"; do bazel --output_base="$BAZEL_CACHE_DIR" clean FILENAME=$(basename "$fullpath") echo "Running test $FILENAME" - sudo env RUST_LOG=info docker compose up -d + # sudo resets the environment, so NATIVELINK_DIR must be passed + # through explicitly or docker compose falls back to mounting + # root's ~/.cache/nativelink instead of the per-run cache dir. + sudo env RUST_LOG=info NATIVELINK_DIR="$NATIVELINK_DIR" docker compose up -d if perl -e 'alarm shift; exec @ARGV' 30 bash -c 'until sudo docker compose logs | grep -q "Ready, listening on"; do sleep 1; done'; then echo "String 'Ready, listening on' found in the logs." else diff --git a/src/bin/nativelink.rs b/src/bin/nativelink.rs index 33e1c6ad5..a5beba1b9 100644 --- a/src/bin/nativelink.rs +++ b/src/bin/nativelink.rs @@ -25,13 +25,14 @@ use clap::Parser; use futures::FutureExt; use futures::future::{BoxFuture, Either, OptionFuture, TryFutureExt, try_join_all}; use hyper::StatusCode; +use hyper_util::rt::TokioTimer; use hyper_util::rt::tokio::TokioIo; use hyper_util::server::conn::auto; use hyper_util::service::TowerToHyperService; use mimalloc::MiMalloc; use nativelink_config::cas_server::{ - CasConfig, GlobalConfig, HttpCompressionAlgorithm, ListenerConfig, SchedulerConfig, - ServerConfig, StoreConfig, WorkerConfig, + CasConfig, CasStoreConfig, GlobalConfig, HttpCompressionAlgorithm, ListenerConfig, + SchedulerConfig, ServerConfig, StoreConfig, WithInstanceName, WorkerConfig, }; use nativelink_config::stores::ConfigDigestHashFunction; use nativelink_error::{Code, Error, ResultExt, make_err, make_input_err}; @@ -45,6 +46,7 @@ use nativelink_service::execution_server::ExecutionServer; use nativelink_service::fetch_server::FetchServer; use nativelink_service::health_server::HealthServer; use nativelink_service::push_server::PushServer; +use nativelink_service::wire_compression::RemoteCacheCompressionInstances; use nativelink_service::worker_api_server::WorkerApiServer; use nativelink_store::default_store_factory::store_factory; use nativelink_store::store_manager::StoreManager; @@ -215,7 +217,9 @@ async fn inner_main( let store = store_factory(&spec, &store_manager, Some(&mut health_register_store)) .await .err_tip(|| format!("Failed to create store '{name}'"))?; - store_manager.add_store(&name, store); + store_manager + .add_store(&name, store) + .err_tip(|| format!("Failed to add store '{name}'"))?; } store_manager.run_post_init().await?; } @@ -263,6 +267,17 @@ async fn inner_main( let server_cfgs: Vec = cfg.servers.into_iter().collect(); + // The capabilities service advertises chunking support for CAS instances + // that may be served from a different server block (e.g. behind an L7 + // router), so collect the CAS configs across all blocks. + let all_cas_configs: Vec> = server_cfgs + .iter() + .filter_map(|server_cfg| server_cfg.services.as_ref()) + .filter_map(|services| services.cas.as_deref()) + .flatten() + .cloned() + .collect(); + for server_cfg in server_cfgs { let services = server_cfg .services @@ -278,6 +293,10 @@ async fn inner_main( .transpose() .err_tip(|| "Could not create Execution service")?; + let capabilities_configs = services.capabilities.as_deref().unwrap_or_default(); + let remote_cache_compression_instances = + RemoteCacheCompressionInstances::from_capabilities_configs(capabilities_configs); + let tonic_services = Routes::builder() .routes() .add_optional_service( @@ -292,8 +311,9 @@ async fn inner_main( .add_optional_service( services .cas + .as_deref() .map_or(Ok(None), |cfg| { - CasServer::new(&cfg, &store_manager) + CasServer::new(cfg, &store_manager, &remote_cache_compression_instances) .map(|v| Some(service_setup!(v.into_service(), http_config))) }) .err_tip(|| "Could not create CAS service")?, @@ -328,18 +348,24 @@ async fn inner_main( services .bytestream .map_or(Ok(None), |cfg| { - ByteStreamServer::new(&cfg, &store_manager) - .map(|v| Some(service_setup!(v.into_service(), http_config))) + ByteStreamServer::new( + &cfg, + &store_manager, + &remote_cache_compression_instances, + ) + .map(|v| Some(service_setup!(v.into_service(), http_config))) }) .err_tip(|| "Could not create ByteStream service")?, ) .add_optional_service( - OptionFuture::from( - services - .capabilities - .as_ref() - .map(|cfg| CapabilitiesServer::new(cfg, &action_schedulers)), - ) + OptionFuture::from(services.capabilities.as_ref().map(|cfg| { + CapabilitiesServer::new( + cfg, + &action_schedulers, + &remote_cache_compression_instances, + &all_cas_configs, + ) + })) .await .map_or(Ok::, Error>(None), |server| { Ok(Some(server?)) @@ -548,6 +574,7 @@ async fn inner_main( .append(format!("Failed to bind to socket address '{socket_addr}'")), })?; let mut http = auto::Builder::new(TaskExecutor::default()); + http.http2().timer(TokioTimer::new()); let http_config = &http_config.advanced_http; if let Some(value) = http_config.http2_keep_alive_interval { diff --git a/src/bin/redis_store_tester.rs b/src/bin/redis_store_tester.rs index b5048161f..4d63757d2 100644 --- a/src/bin/redis_store_tester.rs +++ b/src/bin/redis_store_tester.rs @@ -1,3 +1,4 @@ +use core::pin::Pin; use core::sync::atomic::{AtomicUsize, Ordering}; use core::time::Duration; use std::borrow::Cow; @@ -12,7 +13,7 @@ use nativelink_error::{Code, Error, ResultExt}; use nativelink_store::redis_store::RedisStore; use nativelink_util::buf_channel::make_buf_channel_pair; use nativelink_util::store_trait::{ - SchedulerCurrentVersionProvider, SchedulerIndexProvider, SchedulerStore, + RemoveItemCallback, SchedulerCurrentVersionProvider, SchedulerIndexProvider, SchedulerStore, SchedulerStoreDataProvider, SchedulerStoreDecodeTo, SchedulerStoreKeyProvider, StoreDriver, StoreKey, StoreLike, TrueValue, UploadSizeInfo, }; @@ -155,6 +156,11 @@ async fn run( ) -> Result<(), Error> { let mut count = 0; let in_flight = Arc::new(AtomicUsize::new(0)); + let fixed_action_value = if let Ok(str_action_value) = env::var("ACTION_VALUE") { + Some(str::parse::(&str_action_value).unwrap()) + } else { + None + }; loop { if count % 1000 == 0 { @@ -187,9 +193,13 @@ async fn run( let local_in_flight = in_flight.clone(); let max_action_value = 7; - let action_value = match mode { - TestMode::Random => rand::rng().random_range(0..max_action_value), - TestMode::Sequential => count % max_action_value, + let action_value = if let Some(av) = fixed_action_value { + av + } else { + match mode { + TestMode::Random => rand::rng().random_range(0..max_action_value), + TestMode::Sequential => count % max_action_value, + } }; background_spawn!("action", async move { @@ -222,9 +232,11 @@ async fn run( .await?; } 3 => { + let key = random_key(); store_clone - .update_oneshot(random_key(), Bytes::from_static(b"1234")) + .update_oneshot(key.borrow(), Bytes::from_static(b"1234")) .await?; + info!(?key, "Updated"); } 4 => { let res = store_clone @@ -284,6 +296,19 @@ async fn run( } } +#[derive(Debug)] +struct LoggingRemoveCallback {} + +impl RemoveItemCallback for LoggingRemoveCallback { + fn callback<'a>( + &'a self, + store_key: StoreKey<'a>, + ) -> Pin + Send + 'a>> { + info!(?store_key, "Callback for removed item"); + Box::pin(async {}) + } +} + fn main() -> Result<(), Box> { let args = Args::parse(); let redis_mode: RedisMode = args.redis_mode.into(); @@ -330,10 +355,16 @@ fn main() -> Result<(), Box> { match spec.mode { RedisMode::Standard | RedisMode::Sentinel => { let store = RedisStore::new_standard(spec).await?; + store + .clone() + .register_remove_callback(Arc::new(LoggingRemoveCallback {}))?; run(store, max_loops, failed.clone(), args.mode).await } RedisMode::Cluster => { let store = RedisStore::new_cluster(spec).await?; + store + .clone() + .register_remove_callback(Arc::new(LoggingRemoveCallback {}))?; run(store, max_loops, failed.clone(), args.mode).await } } diff --git a/templates/README.md b/templates/README.md index 2ec132444..56a0ec268 100644 --- a/templates/README.md +++ b/templates/README.md @@ -10,7 +10,7 @@ NativeLink provides the following templates to use caching and remote execution: C/C++ with CMake using [`recc`](https://buildgrid.gitlab.io/recc) as the bridge to NativeLink. Cache-only by default. Compiles run locally and only their outputs travel through the cache. Works on Linux and macOS. - Tutorial: [Build CMake projects with NativeLink](https://nativelink.com/docs/rbe/cmake-recc). + Tutorial: [Build CMake projects with NativeLink](https://docs.nativelink.com/getting-started/other-build-systems/cmake-recc). # Getting started diff --git a/templates/bazel/.github/workflows/lre.yaml b/templates/bazel/.github/workflows/lre.yaml index cb0a24a59..7a81115c7 100644 --- a/templates/bazel/.github/workflows/lre.yaml +++ b/templates/bazel/.github/workflows/lre.yaml @@ -34,4 +34,4 @@ jobs: source-tag: v3.13.0 - name: Build project - run: nix develop --fallback --command bazel build ... + run: nix develop --command bazel-retry build ... diff --git a/templates/cmake/README.md b/templates/cmake/README.md index 13d18b1b2..272399627 100644 --- a/templates/cmake/README.md +++ b/templates/cmake/README.md @@ -1,7 +1,7 @@ # CMake template The full tutorial lives at -[Build CMake projects with NativeLink](https://nativelink.com/docs/rbe/cmake-recc). +[Build CMake projects with NativeLink](https://docs.nativelink.com/getting-started/other-build-systems/cmake-recc). This directory holds the example sources (`CMakeLists.txt`, `main.cpp`) that the tutorial references. Copy them into a fresh project directory diff --git a/toolchain-examples/MODULE.bazel b/toolchain-examples/MODULE.bazel index c37339476..92bd6a872 100644 --- a/toolchain-examples/MODULE.bazel +++ b/toolchain-examples/MODULE.bazel @@ -7,7 +7,7 @@ module( bazel_dep(name = "platforms", version = "1.1.0") # C++ -bazel_dep(name = "rules_cc", version = "0.2.18") +bazel_dep(name = "rules_cc", version = "0.2.20") # Java bazel_dep(name = "rules_java", version = "9.0.3") @@ -34,12 +34,12 @@ python.toolchain( use_repo(pip, "pip") # Go -bazel_dep(name = "rules_go", version = "0.60.0") +bazel_dep(name = "rules_go", version = "0.62.0") # Rust # -bazel_dep(name = "rules_rs", version = "0.0.76") -bazel_dep(name = "llvm", version = "0.7.7") +bazel_dep(name = "rules_rs", version = "0.0.102") +bazel_dep(name = "llvm", version = "0.8.15") rust_toolchains = use_extension("@rules_rs//rs/toolchains:module_extension.bzl", "toolchains") rust_toolchains.toolchain( diff --git a/toolchain-examples/MODULE.bazel.lock b/toolchain-examples/MODULE.bazel.lock index 85e62fbc6..35ec3d853 100644 --- a/toolchain-examples/MODULE.bazel.lock +++ b/toolchain-examples/MODULE.bazel.lock @@ -21,8 +21,6 @@ "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442", "https://bcr.bazel.build/modules/apple_support/1.24.1/MODULE.bazel": "f46e8ddad60aef170ee92b2f3d00ef66c147ceafea68b6877cb45bd91737f5f8", "https://bcr.bazel.build/modules/apple_support/1.24.1/source.json": "cf725267cbacc5f028ef13bb77e7f2c2e0066923a4dab1025e4a0511b1ed258a", - "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/MODULE.bazel": "37c764292861c2f70314efa9846bb6dbb44fc0308903b3285da6528305450183", - "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.3.3/source.json": "605086bbc197743a0d360f7ddc550a1d4dfa0441bc807236e17170f636153348", "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", @@ -42,9 +40,10 @@ "https://bcr.bazel.build/modules/bazel_features/1.36.0/MODULE.bazel": "596cb62090b039caf1cad1d52a8bc35cf188ca9a4e279a828005e7ee49a1bec3", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", "https://bcr.bazel.build/modules/bazel_features/1.42.0/MODULE.bazel": "e8ca15cb2639c5f12183db6dcb678735555d0cdd739b32a0418b6532b5e565f8", - "https://bcr.bazel.build/modules/bazel_features/1.43.0/MODULE.bazel": "defa2226f06ba20550d6548c3a2ea2a7929634437a52973869c20c225450eb91", "https://bcr.bazel.build/modules/bazel_features/1.45.0/MODULE.bazel": "7daec6d87ab0703417486d4cb948af0b06f55d4d7c08cbb5978c80e79b538edf", - "https://bcr.bazel.build/modules/bazel_features/1.45.0/source.json": "635e4536e09ff125b8972e0fa239c135fde5f18701f7d5115680560651dfb41d", + "https://bcr.bazel.build/modules/bazel_features/1.47.0/MODULE.bazel": "e34df3cb35b1684cfa69923a61ae3803595babd3942cd306a488d51400886b30", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/MODULE.bazel": "2083ef9c7a469f520890483ccf8e0189d6e71e2117e7752e15e6554433d5ae3e", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/source.json": "e0ee3debde2789ff56e4452e612d126925ba9ab64d4bde79c67f099d2902df9b", "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d", @@ -70,6 +69,8 @@ "https://bcr.bazel.build/modules/boringssl/0.20241024.0/source.json": "d843092e682b84188c043ac742965d7f96e04c846c7e338187e03238674909a9", "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/MODULE.bazel": "29ecf4babfd3c762be00d7573c288c083672ab60e79c833ff7f49ee662e54471", + "https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/source.json": "8be4a3ef2599693f759e5c0990a4cc5a246ac08db4c900a38f852ba25b5c39be", "https://bcr.bazel.build/modules/circl/1.3.8/MODULE.bazel": "1caeccc623ec319444e58040ac600d02ca723905155276fa1f1dd9744e580780", "https://bcr.bazel.build/modules/circl/1.3.8/source.json": "5ff347710530a6f4d8b364d251618f883f0e9210ae474726c6da7f69c64fb4e3", "https://bcr.bazel.build/modules/curl/8.8.0.bcr.3/MODULE.bazel": "df703a5a606a5bc264a95940113daa44197dc211f51230dd058323f2aa50efca", @@ -80,7 +81,8 @@ "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", - "https://bcr.bazel.build/modules/gazelle/0.36.0/source.json": "0823f097b127e0201ae55d85647c94095edfe27db0431a7ae880dcab08dfaa04", + "https://bcr.bazel.build/modules/gazelle/0.51.3/MODULE.bazel": "618a729142f66de1e2cb776d026413763be5b80d5e3d29ffb9d3d90c5defde90", + "https://bcr.bazel.build/modules/gazelle/0.51.3/source.json": "fbe5312a01fb4a2a58caff4a0d40dcf384b6f0bda75e85546663360da1d7538a", "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", @@ -90,18 +92,22 @@ "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", "https://bcr.bazel.build/modules/hermetic_cc_toolchain/4.0.1/MODULE.bazel": "0809d28e562d804e478c683b06a9f3adeedccfdb42a426c2cc69e39cbc7e3bf3", "https://bcr.bazel.build/modules/hermetic_cc_toolchain/4.0.1/source.json": "527d73a9964cd34ceeb73a1d5e5d04d9e6238401363c783c1f3021d5b25b8a63", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.8/MODULE.bazel": "3be7b0faca6f1e69e89197999e0b01ce058c42f3e764ef028466f7e0ff77c761", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.8/source.json": "8403718636114198fca6ea04b437fa001ac7167b4d485102defb0a6f7d11bc08", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", - "https://bcr.bazel.build/modules/llvm/0.7.7/MODULE.bazel": "0eeaf1814feca77abc7af3523e2b9d3735f92e2583043f8d6a2cc0fb5f479a28", - "https://bcr.bazel.build/modules/llvm/0.7.7/source.json": "7c8910307329462a21b7bdcc52710360da3de8284738dca52241bb15302a00dc", + "https://bcr.bazel.build/modules/llvm/0.8.15/MODULE.bazel": "2a6f808abd87d6037a435d98816b46ccb4773caa4b1923dea5c02d0a21c9dc19", + "https://bcr.bazel.build/modules/llvm/0.8.15/source.json": "994db3a9052966be153f329219ee9ef163ecbc1e505bbd78079af14c1e24f767", + "https://bcr.bazel.build/modules/llvm/0.8.9/MODULE.bazel": "9e35ff5bcac996f9edc1b44b8f8baa58c7855e742c5608b07d925dcdbe642100", "https://bcr.bazel.build/modules/mbedtls/3.6.0/MODULE.bazel": "8e380e4698107c5f8766264d4df92e36766248447858db28187151d884995a09", "https://bcr.bazel.build/modules/mbedtls/3.6.0/source.json": "1dbe7eb5258050afcc3806b9d43050f71c6f539ce0175535c670df606790b30c", "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", "https://bcr.bazel.build/modules/openssl/3.3.1.bcr.1/MODULE.bazel": "49c0c07e8fb87b480bccb842cfee1b32617f11dac590f732573c69058699a3d1", "https://bcr.bazel.build/modules/openssl/3.3.1.bcr.1/source.json": "0c0872e048bbea052a9c541fb47019481a19201ba5555a71d762ad591bf94e1f", "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/MODULE.bazel": "ef4f9439e3270fdd6b9fd4dbc3d2f29d13888e44c529a1b243f7a31dfbc2e8e4", "https://bcr.bazel.build/modules/package_metadata/0.0.7/MODULE.bazel": "7adb03933fc8401f495800cf4eafcff0edc6da0ff55c7db223ef69d19f689486", "https://bcr.bazel.build/modules/package_metadata/0.0.7/source.json": "50639625e937b56115012674c797cca7a05a96b4878c87d803c13dc2b31de8a0", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", @@ -118,6 +124,7 @@ "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2.bcr.1/MODULE.bazel": "52f4126f63a2f0bbf36b99c2a87648f08467a4eaf92ba726bc7d6a500bbf770c", "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", @@ -153,8 +160,9 @@ "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37", - "https://bcr.bazel.build/modules/rules_cc/0.2.18/MODULE.bazel": "4460ec36adc8f722a6a2a4ac9374cb91f2acebadaa93fc37966129afb3dece87", - "https://bcr.bazel.build/modules/rules_cc/0.2.18/source.json": "abad668ff2fd63ada1ac49bf386d37e27048b89a3465a6fd968bb832b00a09d3", + "https://bcr.bazel.build/modules/rules_cc/0.2.19/MODULE.bazel": "d5e0f05b63273281a16654eb6b1a8742a75ec153ac8b4f0419949d6e401e46f0", + "https://bcr.bazel.build/modules/rules_cc/0.2.20/MODULE.bazel": "f5c07bce5ddcb99be21a0812ff5aadb439e688b7449c6542152363b2fd859c1a", + "https://bcr.bazel.build/modules/rules_cc/0.2.20/source.json": "1155433dc6b8161bc339ce94095b337ed95feb1f048b014e10b62339d4b4239c", "https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc", "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642", "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", @@ -163,8 +171,9 @@ "https://bcr.bazel.build/modules/rules_go/0.42.0/MODULE.bazel": "8cfa875b9aa8c6fce2b2e5925e73c1388173ea3c32a0db4d2b4804b453c14270", "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd", "https://bcr.bazel.build/modules/rules_go/0.48.0/MODULE.bazel": "d00ebcae0908ee3f5e6d53f68677a303d6d59a77beef879598700049c3980a03", - "https://bcr.bazel.build/modules/rules_go/0.60.0/MODULE.bazel": "4a57ff2ffc2a3570e3c5646575c5a4b07287e91bcdac5d1f72383d51502b48cb", - "https://bcr.bazel.build/modules/rules_go/0.60.0/source.json": "1e21368c5e0c3013a110bd79a8fcff8ca46b5bcb2b561713a7273cbfcff7c464", + "https://bcr.bazel.build/modules/rules_go/0.59.0/MODULE.bazel": "b7e43e7414a3139a7547d1b4909b29085fbe5182b6c58cbe1ed4c6272815aeae", + "https://bcr.bazel.build/modules/rules_go/0.62.0/MODULE.bazel": "8ee616065c3d2b2f7ac0880108316ce8d0c332b3a30aad24e95c0bc124ec853e", + "https://bcr.bazel.build/modules/rules_go/0.62.0/source.json": "36d781c558eb7d3bd49dc5e190455714f174232372f15207ab200b4348bda3e6", "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", @@ -224,8 +233,8 @@ "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", "https://bcr.bazel.build/modules/rules_python/2.0.0/MODULE.bazel": "1459089e2d4194d2a49e07896f5334fb230a8f2966ae945b1f793bef87a292fd", "https://bcr.bazel.build/modules/rules_python/2.0.0/source.json": "b8e25661f58c573e5e27af21295867e87766e89211f326fcb84034e6e6b6794b", - "https://bcr.bazel.build/modules/rules_rs/0.0.76/MODULE.bazel": "461dcf664f368fdc921f67ea20ec1bc78c73f65a0a20b6e2a6d4b1c77fbde8c1", - "https://bcr.bazel.build/modules/rules_rs/0.0.76/source.json": "167eb1122e0f74848fc995b581061155dda1dfd600a38c253a85ef46d0523221", + "https://bcr.bazel.build/modules/rules_rs/0.0.102/MODULE.bazel": "6c64a272531e59dc2a55726117a4ca3161c6301fd69af3bd1038465730e86632", + "https://bcr.bazel.build/modules/rules_rs/0.0.102/source.json": "e0bb950a7126037e2bf5b341e88012fd393d68715489dccce54780f50e6df9ca", "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", @@ -240,13 +249,15 @@ "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", - "https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445", - "https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/MODULE.bazel": "e8f9ff79199e8d9eaad7f1b0a77ad74b30bb82d794b87d8ca942bead5de83ae9", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/source.json": "20143442376c03426f6135292ba02d825cb75308aa47e6bf42dd4cc5a435c2ff", "https://bcr.bazel.build/modules/toolchains_llvm/1.3.0/MODULE.bazel": "6e02731e51f7eb2ec4b01c5e79e722bf738a631f6e03d9b4917cbf2cb027bee1", "https://bcr.bazel.build/modules/toolchains_llvm/1.3.0/source.json": "4ce0373a89c6df34dd37cd67285bb871d8e225d30dcb67dd093e077a04bbbb71", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/MODULE.bazel": "b573395fe63aef4299ba095173e2f62ccfee5ad9bbf7acaa95dba73af9fc2b38", "https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/source.json": "3f3fbaeafecaf629877ad152a2c9def21f8d330d91aa94c5dc75bbb98c10b8b8", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.8/MODULE.bazel": "e48a69bd54053c2ec5fffc2a29fb70122afd3e83ab6c07068f63bc6553fa57cc", + "https://bcr.bazel.build/modules/xz/5.4.5.bcr.8/source.json": "bd7e928ccd63505b44f4784f7bbf12cc11f9ff23bf3ca12ff2c91cd74846099e", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", @@ -257,6 +268,54 @@ }, "selectedYankedVersions": {}, "moduleExtensions": { + "@@protobuf+//python/dist:system_python.bzl%system_python_extension": { + "general": { + "bzlTransitiveDigest": "pmsA+awieucfllLc2n7k8xEoPp0i5LF9Hw6mGX0cqSQ=", + "usagesDigest": "A+RWmbKdBBwZcBbNGNvfPbqG2vYZRjVrFp6x1iRUrAk=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "system_python": { + "repoRuleId": "@@protobuf+//python/dist:system_python.bzl%system_python", + "attributes": { + "minimum_python_version": "3.9" + } + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { + "general": { + "bzlTransitiveDigest": "G7xCmtNWXRuBtChRgB5OK5+gmM8Uoy8Mec/B7j3fhqs=", + "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=", + "recordedFileInputs": { + "@@pybind11_bazel+//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" + }, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "pybind11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel", + "strip_prefix": "pybind11-2.12.0", + "urls": [ + "https://github.com/pybind/pybind11/archive/v2.12.0.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "pybind11_bazel+", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { "general": { "bzlTransitiveDigest": "OlvsB0HsvxbR8ZN+J9Vf00X/+WVz/Y/5Xrq2LgcVfdo=", @@ -321,6 +380,80 @@ ] } }, + "@@rules_perl+//perl:extensions.bzl%perl_repositories": { + "general": { + "bzlTransitiveDigest": "2b+Kf0VvFQTw7hCgirLBKaJFU952JUAVdFELnLdMuf0=", + "usagesDigest": "qSSNDdCNVxNhY36wMndEAFacdhR0ooLTmumfad0km9s=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "perl_darwin_arm64": { + "repoRuleId": "@@rules_perl+//perl:repo.bzl%perl_download", + "attributes": { + "strip_prefix": "perl-darwin-arm64", + "sha256": "285769f3c50c339fb59a3987b216ae3c5c573b95babe6875a1ef56fb178433da", + "urls": [ + "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-darwin-arm64.tar.xz" + ] + } + }, + "perl_darwin_amd64": { + "repoRuleId": "@@rules_perl+//perl:repo.bzl%perl_download", + "attributes": { + "strip_prefix": "perl-darwin-amd64", + "sha256": "63bc5ee36f5394d71c50cca6cafdd333ee58f9eaa40bca63c85f9bd06f2c1fd6", + "urls": [ + "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-darwin-amd64.tar.xz" + ] + } + }, + "perl_linux_amd64": { + "repoRuleId": "@@rules_perl+//perl:repo.bzl%perl_download", + "attributes": { + "strip_prefix": "perl-linux-amd64", + "sha256": "3bdffa9d7a3f97c0207314637b260ba5115b1d0829f97e3e2e301191a4d4d076", + "urls": [ + "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-linux-amd64.tar.xz" + ] + } + }, + "perl_linux_arm64": { + "repoRuleId": "@@rules_perl+//perl:repo.bzl%perl_download", + "attributes": { + "strip_prefix": "perl-linux-arm64", + "sha256": "6fa4ece99e790ecbc2861f6ecb7b52694c01c2eeb215b4370f16a3b12d952117", + "urls": [ + "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-linux-arm64.tar.xz" + ] + } + }, + "perl_windows_x86_64": { + "repoRuleId": "@@rules_perl+//perl:repo.bzl%perl_download", + "attributes": { + "strip_prefix": "", + "sha256": "aeb973da474f14210d3e1a1f942dcf779e2ae7e71e4c535e6c53ebabe632cc98", + "urls": [ + "https://mirror.bazel.build/strawberryperl.com/download/5.32.1.1/strawberry-perl-5.32.1.1-64bit.zip", + "https://strawberryperl.com/download/5.32.1.1/strawberry-perl-5.32.1.1-64bit.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_perl+", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_perl+", + "rules_perl", + "rules_perl+" + ] + ] + } + }, "@@rules_python+//python/uv:uv.bzl%uv": { "general": { "bzlTransitiveDigest": "+utyaJTX+MwR5wSbJE2C/rUQR1A+kg2Ywwk3CjDOEkg=", diff --git a/toolchain-examples/rbe-toolchain-test.nix b/toolchain-examples/rbe-toolchain-test.nix index 5746fe7fb..e476ff6b8 100644 --- a/toolchain-examples/rbe-toolchain-test.nix +++ b/toolchain-examples/rbe-toolchain-test.nix @@ -1,8 +1,9 @@ { nativelink, writeShellScriptBin, - bazelisk, jo, + bazel-retry, + bazel, }: writeShellScriptBin "rbe-toolchain-test" '' set -uo pipefail @@ -63,7 +64,7 @@ writeShellScriptBin "rbe-toolchain-test" '' run_cmd() { cmd=$1 - FULL_CMD="${bazelisk}/bin/bazelisk $cmd $CORE_BAZEL_ARGS" + FULL_CMD="PATH=${bazel}/bin:$PATH ${bazel-retry}/bin/bazel-retry $cmd $CORE_BAZEL_ARGS" echo $FULL_CMD echo -e \\n$FULL_CMD\\n >> toolchain-examples/cmd.log cmd_output=$(cd toolchain-examples && eval "$FULL_CMD" 2>&1 | tee -ai cmd.log) diff --git a/tools/bazel-retry.sh b/tools/bazel-retry.sh new file mode 100755 index 000000000..7b151c49e --- /dev/null +++ b/tools/bazel-retry.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -o pipefail +BAZEL_LOG=$(mktemp -t) +# Bazel's downloader retry only covers truncated downloads, not HTTP 5xx/403 failures, +# so a flaky fetch aborts the build with no retry. We retry the download in this case. +delay=5 +for attempt in 1 2 3; do + if exec bazel "$@" 2>&1 | tee "${BAZEL_LOG}"; then + exit 0 + fi + grep -E '^ERROR:' "${BAZEL_LOG}" | + grep -Eq 'GET returned (403|429|5[0-9][0-9])|Bad Gateway|Connection (reset|timed out)|read timed out|Could not resolve host' || { + echo "Bazel failed (non-transient); not retrying" + exit 1 + } + [ "$attempt" -lt 3 ] || break + echo "Transient fetch error (attempt ${attempt}); retrying in ${delay}s..." + sleep "$delay" + delay=$((delay * 2)) +done +echo "Bazel still failing after 3 attempts." +exit 1 diff --git a/tools/cargo-llvm-cov/Cargo.lock b/tools/cargo-llvm-cov/Cargo.lock index 40fa992bb..c8499e41a 100644 --- a/tools/cargo-llvm-cov/Cargo.lock +++ b/tools/cargo-llvm-cov/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "autocfg" diff --git a/tools/cargo-llvm-cov/osv-scanner.toml b/tools/cargo-llvm-cov/osv-scanner.toml new file mode 100644 index 000000000..143a6e642 --- /dev/null +++ b/tools/cargo-llvm-cov/osv-scanner.toml @@ -0,0 +1,9 @@ +# Ignore false positives as per https://github.com/taiki-e/cargo-llvm-cov/blob/main/.deny.toml + +[[IgnoredVulns]] +id = "RUSTSEC-2026-0194" +reason = "quick-xml (via lcov2cobertura). Not affected since lcov2cobertura emits xml, but doesn't parse." + +[[IgnoredVulns]] +id = "RUSTSEC-2026-0195" +reason = "quick-xml (via lcov2cobertura). Not affected since lcov2cobertura doesn't use affected APIs." diff --git a/tools/generate-bazel-rc/src/main.rs b/tools/generate-bazel-rc/src/main.rs index a0d54021b..1debc5285 100644 --- a/tools/generate-bazel-rc/src/main.rs +++ b/tools/generate-bazel-rc/src/main.rs @@ -76,7 +76,7 @@ fn get_lints_from_key(lints_table: &Map, key: &str) -> BTreeSet $HOME/.node-gyp/${nodejs.version}/installVersion - ln -sfv ${nodejs}/include $HOME/.node-gyp/${nodejs.version} - export npm_config_nodedir=${nodejs} - npm run rebuild - rm -rf build/Release/{obj.target,.deps} vendor - - popd - - pushd node_modules/.pnpm/better-sqlite3*/node_modules/better-sqlite3 - npm run build-release - rm -rf build/Release/{obj.target,sqlite3.a,.deps} deps - - popd - - runHook postBuild - ''; - - # TODO: replace with `pnpm deploy` - # now it fails to build with ERR_PNPM_NO_OFFLINE_META - # see https://github.com/pnpm/pnpm/issues/5315 - installPhase = '' - runHook preInstall - - mkdir -p $out/{bin,lib/node_modules/renovate} - cp -r dist node_modules package.json renovate-schema.json $out/lib/node_modules/renovate - - makeWrapper "${lib.getExe nodejs}" "$out/bin/renovate" \ - --add-flags "$out/lib/node_modules/renovate/dist/renovate.js" - makeWrapper "${lib.getExe nodejs}" "$out/bin/renovate-config-validator" \ - --add-flags "$out/lib/node_modules/renovate/dist/config-validator.js" - - runHook postInstall - ''; - - passthru = { - tests = { - version = testers.testVersion {package = finalAttrs.finalPackage;}; - vm-test = nixosTests.renovate; - }; - updateScript = nix-update-script { - extraArgs = [ - "--version-regex" - "^(\\d+\\.\\d+\\.\\d+)$" - ]; - }; - }; - - meta = { - description = "Cross-platform Dependency Automation by Mend.io"; - homepage = "https://github.com/renovatebot/renovate"; - changelog = "https://github.com/renovatebot/renovate/releases/tag/${finalAttrs.version}"; - license = lib.licenses.agpl3Only; - maintainers = with lib.maintainers; [ - marie - natsukium - ]; - mainProgram = "renovate"; - inherit (nodejs.meta) platforms; - }; - }) diff --git a/tools/toolchain-buck2/Dockerfile b/tools/toolchain-buck2/Dockerfile index 313681e8f..e2d44c960 100644 --- a/tools/toolchain-buck2/Dockerfile +++ b/tools/toolchain-buck2/Dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive \ apt-get install -y --no-install-recommends \ git=1:2.43.0-1ubuntu7.3 \ ca-certificates=20240203 \ - curl=8.5.0-2ubuntu10.9 \ + curl=8.5.0-2ubuntu10.11 \ python3=3.12.3-0ubuntu2.1 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ diff --git a/tools/toolchain-nativelink/Dockerfile b/tools/toolchain-nativelink/Dockerfile index 84bf8c59f..d13f8b49f 100644 --- a/tools/toolchain-nativelink/Dockerfile +++ b/tools/toolchain-nativelink/Dockerfile @@ -23,7 +23,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-instal gcc=4:13.2.0-7ubuntu1 \ g++=4:13.2.0-7ubuntu1 \ python3=3.12.3-0ubuntu2.1 \ - curl=8.5.0-2ubuntu10.9 \ + curl=8.5.0-2ubuntu10.11 \ ca-certificates=20240203 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/typos.toml b/typos.toml index 356f7e4ba..d6efd4c10 100644 --- a/typos.toml +++ b/typos.toml @@ -1,6 +1,8 @@ [default.extend-words] # `conly_flags` in lre-cc conly = "conly" +# in-toto attestation format used by SLSA provenance (`*.intoto.jsonl`) +intoto = "intoto" [default] # Old wrong spelling support diff --git a/web/DEPLOYMENT.md b/web/DEPLOYMENT.md index 42eff2926..512df6f04 100644 --- a/web/DEPLOYMENT.md +++ b/web/DEPLOYMENT.md @@ -96,6 +96,32 @@ docs project's main-branch production. If you want a preview to proxy to the docs project's branch preview, you'd need a build-time hook to rewrite `DOCS_URL`; we haven't wired that yet. +## Generated content + +The docs changelog page (`/reference/changelog`) is not checked in. It is +generated from the repository-root `CHANGELOG.md` — the canonical changelog +git-cliff maintains at release time — by +`apps/docs/scripts/gen-changelog.mjs`, which runs at the start of the docs +`dev` and `build` scripts. Every merge to main therefore republishes the +page from the current changelog, and the web CI build on pull requests +fails if a changelog edit stops compiling. The page is emitted as plain +markdown (`changelog.md`, not `.mdx`) so JSX- and import-like text in +commit subjects is inert rather than syntax. + +The script reads `CHANGELOG.md` from disk when the repository root is +available (local checkouts, GitHub CI, Vercel with **Include source files +outside of the Root Directory** enabled). Vercel's default build container +only mounts the workspace, so there the script instead fetches the file +from GitHub raw pinned to `VERCEL_GIT_COMMIT_SHA` — the exact commit being +deployed, so the bytes match a full checkout. If neither works the build +fails with instructions rather than publishing a stale page. + +Because of this, don't configure an **Ignored Build Step** on the docs +Vercel project that skips builds when `web/` is unchanged: a release merge +touches only root files (`CHANGELOG.md`, version bumps), and skipping that +deploy would leave the published changelog stale until the next `web/` +change. + ## Operating - **Cache invalidation**: Vercel handles automatic edge invalidation on diff --git a/web/apps/docs/.gitignore b/web/apps/docs/.gitignore index 0abf60296..02bf83b1b 100644 --- a/web/apps/docs/.gitignore +++ b/web/apps/docs/.gitignore @@ -4,3 +4,7 @@ out/ .source/ next-env.d.ts *.tsbuildinfo + +# Generated from the repository-root CHANGELOG.md by scripts/gen-changelog.mjs +# (runs as part of `dev` and `build`). +content/docs/reference/changelog.md diff --git a/web/apps/docs/app/layout.tsx b/web/apps/docs/app/layout.tsx index c75ccf195..d6738f77c 100644 --- a/web/apps/docs/app/layout.tsx +++ b/web/apps/docs/app/layout.tsx @@ -1,4 +1,5 @@ import { source } from "@/lib/source"; +import { GoogleTagManager } from "@next/third-parties/google"; import { DocsLayout } from "fumadocs-ui/layouts/docs"; import { RootProvider } from "fumadocs-ui/provider/next"; import { GeistMono } from "geist/font/mono"; @@ -24,6 +25,7 @@ export default function RootLayout({ children }: { children: ReactNode }) { suppressHydrationWarning className={`${GeistSans.variable} ${GeistMono.variable}`} > + {/* RootProvider configures the theme via next-themes. Setting BOTH * "class" and "data-theme" attributes is intentional: diff --git a/web/apps/docs/content/docs/configuration/basic.mdx b/web/apps/docs/content/docs/configuration/basic.mdx index 6e6e87f02..0003e2494 100644 --- a/web/apps/docs/content/docs/configuration/basic.mdx +++ b/web/apps/docs/content/docs/configuration/basic.mdx @@ -176,6 +176,63 @@ actions, add a scheduler and at least one worker: Now the cluster will execute actions in addition to caching them. +## Aligning digest functions + +Every NativeLink server, worker, and build client sharing a cache must +use the same digest function. SHA-256 and BLAKE3 produce different +cache keys for the same bytes, so uploads made with one function are +cache misses for clients using the other. + +NativeLink defaults to SHA-256. Keep the default explicit in every +NativeLink configuration: + +```json5 +{ + global: { + max_open_files: 24576, + default_digest_hash_function: "sha256", + }, + // ... stores, servers, schedulers, and workers ... +} +``` + +Then configure Bazel clients to match in `.bazelrc`: + +```text +startup --digest_function=sha256 +``` + +If your clients use BLAKE3 instead, set both values to `blake3`. +NativeLink accepts an explicitly declared non-default function, but it +logs a warning because mixed digest functions divide the cache and +reduce shared cache hits. + +### NativeLink build benchmark + +We compared both algorithms on an Apple M2 Max with 12 CPU cores and +32 GB of memory, running macOS 15.6 and Bazel 9.1.1. Each of two +alternating runs built `//:nativelink` against a fresh local +NativeLink filesystem cache with hash and size verification enabled. +Uploads were synchronous, and the Bazel output and NativeLink cache +directories were isolated by algorithm. + +| Phase | SHA-256 runs | SHA-256 mean | BLAKE3 runs | BLAKE3 mean | +| --- | --- | ---: | --- | ---: | +| Compile and populate an empty cache | 179.90 s, 180.18 s | 180.04 s | 181.56 s, 185.57 s | 183.57 s | +| Rebuild from the populated cache | 6.39 s, 5.93 s | 6.16 s | 6.74 s, 6.41 s | 6.58 s | + +Both population builds performed 2,620 actions. Each cached rebuild +reported 1,458 remote cache hits. SHA-256 was 1.9% faster while +populating the cache and 6.3% faster on the cached rebuild in this +test, so SHA-256 remains the default. + +These are whole-build measurements from one macOS machine, not a +universal hashing benchmark. Compilation, storage, scheduling, and +operating-system caching dominate much of the elapsed time. Measure +your own representative workload before changing algorithms; keeping +every participant aligned matters more than a small isolated timing +difference. + ## Choosing instance names The `instance_name` field appears everywhere. It namespaces every @@ -193,6 +250,27 @@ Every client targeting a given cache must use the same `instance_name`. Mismatches don't produce errors; they produce silently-empty caches. +## FAQ + + + + Each store's `eviction_policy.max_bytes` caps it; once full, the + least-recently-used entries are evicted to make room. An evicted + entry is just a future cache miss — clients rebuild and re-upload. + + + The scheduler's `supported_platform_properties` must be satisfiable + by at least one worker's `platform_properties`, or matching actions + queue indefinitely with no error surfaced. Compare those two blocks + first. + + + When more than one node needs the same cache, or when a restart + wiping state starts to hurt. That's the cue for the durable, sharded + shapes in [Production configurations](/configuration/production). + + + ## What's next - [Production configurations](/configuration/production) — the diff --git a/web/apps/docs/content/docs/configuration/chunking.mdx b/web/apps/docs/content/docs/configuration/chunking.mdx new file mode 100644 index 000000000..bfa28bda1 --- /dev/null +++ b/web/apps/docs/content/docs/configuration/chunking.mdx @@ -0,0 +1,133 @@ +--- +title: Content-defined chunking +description: Cut remote cache transfer bytes by 80-90% for incrementally changing artifacts with the REAPI SplitBlob/SpliceBlob extension and Bazel's --experimental_remote_cache_chunking. +--- + +When a large build output changes slightly — a relinked binary, a container +layer with one file modified — its digest changes, and a conventional remote +cache re-transfers the whole blob. Content-defined chunking (CDC) splits +blobs into chunks at content-derived boundaries, so clients upload and +download only the chunks that actually changed. In our measurements a +one-file change to a 16.8 MB tar layer re-uploaded 2.1 MB (87.5% less), and +a one-source-file change to a linked binary re-uploaded 80.8% less. + +NativeLink implements the server side of the +[REAPI blob split/splice extension](https://github.com/bazelbuild/remote-apis/pull/282): +`SpliceBlob` re-assembles chunked uploads (verifying the digest before +committing anything), and `SplitBlob` serves chunk layouts for downloads — +chunking blobs on demand with FastCDC 2020 when they were uploaded whole, +which is what makes chunked downloads work for outputs produced by remote +execution workers. + +## Requirements + +- **Bazel 9.1.1+ or 8.7.0+** on the client, with + `--experimental_remote_cache_chunking`. Avoid 9.1.0: it has a client bug + that corrupts outputs when the chunking flag is combined with + `--disk_cache` (fixed in 9.1.1). +- Chunking is **optional and off by default**. Without the configuration + below, NativeLink behaves exactly as before and does not advertise + chunking support, so clients fall back to regular transfers. + +## Enabling it + +Add an `experimental_chunking` block to the CAS service and give it a small +store for chunk layouts. The index store must not verify content digests +and must not be the CAS store itself: + +```json5 +stores: [ + { + name: "CAS_MAIN_STORE", + // ... your existing CAS store ... + }, + { + // Blob-to-chunks layouts: roughly 80-140 bytes per chunk. + name: "CHUNK_INDEX_STORE", + filesystem: { + content_path: "/tmp/nativelink/data/content_path-chunk-index", + temp_path: "/tmp/nativelink/data/tmp_path-chunk-index", + eviction_policy: { max_bytes: 100000000 }, + }, + }, +], +servers: [ + { + // ... + services: { + cas: [ + { + cas_store: "CAS_MAIN_STORE", + experimental_chunking: { + index_store: "CHUNK_INDEX_STORE", + // Optional; the REAPI-recommended default. Must be between + // 1 KiB and 1 MiB. Blobs smaller than 4x this value are + // never chunked. + avg_chunk_size_bytes: 524288, + // Optional; blobs producing more chunks than this are served + // without chunking (~25 GiB at the default average). + max_chunk_count: 50000, + }, + }, + ], + // The capabilities service advertises chunking support; clients + // only use it when advertised. + capabilities: [{}], + // ... + }, + }, +], +``` + +A complete runnable example lives at +[`nativelink-config/examples/chunking_cas.json5`](https://github.com/TraceMachina/nativelink/blob/main/nativelink-config/examples/chunking_cas.json5). +For instances whose `cas_store` is a grpc proxy store, omit `index_store`: +the chunking RPCs are forwarded to the backend, which owns the layouts. + +Then build with: + +```sh +bazel build //... \ + --remote_cache=grpc://your-nativelink:50051 \ + --experimental_remote_cache_chunking +``` + +## When it helps, and when it doesn't + +Chunking pays off when clients reach the cache across a real network (WAN, +metered links, cross-region) and artifacts change incrementally: +uncompressed archives, linked binaries, and container layers typically save +80–90% of transfer bytes per change. It does little on same-rack links — +saved bytes only save time when the wire is the bottleneck — and little for +compressed artifacts, where everything after the first changed byte +re-transfers. Small blobs (below 4x the average chunk size) are never +chunked, so hot small-object traffic is unaffected. + +The server verifies every spliced blob's digest before committing it and +materializes the full blob, so non-chunking clients and every existing read +path see ordinary blobs. Storage grows by roughly the chunk bytes for +chunk-eligible blobs; pairing the CAS with a `dedup` or `compression` store +composes normally. + +## FAQ + + + + No. Chunking is opt-in and advertised through the capabilities + service — clients that don't request it (or predate it) keep using + regular transfers against the same CAS. + + + Bazel 9.1.0 has a client bug that corrupts outputs when the chunking + flag is combined with `--disk_cache`. Use 9.1.1+ (or 8.7.0+). + + + They solve different transfer problems. Chunking re-transfers only + the changed parts of large, incrementally-changing blobs; + [wire compression](/configuration/compression) shrinks compressible + blobs wholesale. Compressed artifacts chunk poorly — everything after + the first changed byte re-transfers — so lean on chunking for + archives, binaries, and layers, and on compression for text-heavy + outputs. + + diff --git a/web/apps/docs/content/docs/configuration/compression.mdx b/web/apps/docs/content/docs/configuration/compression.mdx new file mode 100644 index 000000000..2422d0a6c --- /dev/null +++ b/web/apps/docs/content/docs/configuration/compression.mdx @@ -0,0 +1,212 @@ +--- +title: Remote cache compression +description: Cut remote cache transfer bytes for compressible artifacts with REAPI zstd wire compression and Bazel's --remote_cache_compression. +--- + +Build artifacts are often highly compressible — object files, archives, +test logs — but a conventional remote cache transfers them byte-for-byte. +With wire compression, clients and server exchange blobs as zstd-compressed +streams and only the wire bytes shrink: NativeLink decompresses on upload +and compresses on download at the gRPC boundary, so stores keep raw, +uncompressed bytes and every existing read path sees ordinary blobs. + +NativeLink implements the server side of the REAPI +[`compressed-blobs`](https://github.com/bazelbuild/remote-apis/blob/main/build/bazel/remote/execution/v2/remote_execution.proto) +extension with `zstd` as the only supported non-identity compressor, +matching what Bazel's `--remote_cache_compression` flag speaks: ByteStream +reads and writes use `compressed-blobs/zstd/...` resource names, and the +CAS batch RPCs accept and serve zstd-compressed payloads. + +## Requirements + +- A Bazel client with `--remote_cache_compression` (available since + Bazel 5). +- Wire compression is **optional and off until it is enabled somewhere in + the NativeLink process**. Without the configuration below or an explicitly + enabled CAS gRPC store, NativeLink does not advertise zstd, rejects + `compressed-blobs/zstd` requests, and keeps outgoing transfers on the + identity path. + +## Enabling it + +Set `remote_cache_compression: true` on the capabilities service for the +instance. The capabilities service advertises zstd to clients, and the +ByteStream and CAS services accept and serve compressed payloads for that +instance: + +```json5 +servers: [ + { + // ... + services: { + cas: [{ instance_name: "main", cas_store: "CAS_MAIN_STORE" }], + bytestream: [{ instance_name: "main", cas_store: "CAS_MAIN_STORE" }], + capabilities: [ + { + instance_name: "main", + remote_cache_compression: true, + }, + ], + // ... + }, + }, +], +``` + +Then build with: + +```sh +bazel build //... \ + --remote_cache=grpc://your-nativelink:50051 \ + --remote_cache_compression +``` + +Clients only compress when the server advertises it, so enabling the +option is safe with a mixed fleet of clients: anything that doesn't request +`compressed-blobs/zstd` keeps using identity transfers. + +### NativeLink-to-NativeLink transfers + +Enabling zstd on any capabilities instance or CAS `grpc` store expresses +process-wide zstd intent. NativeLink then automatically enables every CAS +`grpc` store whose `experimental_remote_cache_compression` setting is +omitted. This makes worker-to-CAS and proxy-to-upstream blob transfers use +zstd without requiring the same setting to be repeated on every eligible +store. + +#### Keeping compression consistent + +Don't enable zstd on some CAS `grpc` stores while explicitly disabling it +on others. Inconsistent settings mean the disabled legs keep moving +identity bytes — often on exactly the links that carry the most data — so +blobs that cross both legs are compressed on one hop only to travel +uncompressed on the next: + +```json5 +// Avoid: inconsistent compression across CAS stores. +stores: [ + { + name: "CAS_PRIMARY", + grpc: { + endpoints: [{ address: "grpc://cas-primary:50051" }], + store_type: "cas", + experimental_remote_cache_compression: true, + }, + }, + { + name: "CAS_MIRROR", + grpc: { + endpoints: [{ address: "grpc://cas-mirror:50051" }], + store_type: "cas", + // This leg stays on identity transfers while zstd is enabled + // elsewhere in the process; NativeLink logs a startup warning + // suggesting you enable zstd throughout. + experimental_remote_cache_compression: false, + }, + }, +], +``` + +Instead, declare the intent once and let the inheritance policy carry it: +enable zstd on the capabilities service (or any one CAS `grpc` store) and +omit the setting everywhere else, so every eligible store inherits it: + +```json5 +// Prefer: declare zstd intent once; eligible stores inherit it. +servers: [ + { + // ... + services: { + capabilities: [ + { instance_name: "main", remote_cache_compression: true }, + ], + }, + }, +], +stores: [ + { + name: "CAS_PRIMARY", + grpc: { + endpoints: [{ address: "grpc://cas-primary:50051" }], + store_type: "cas", + // Inherits zstd from the process-wide intent. + }, + }, + { + name: "CAS_MIRROR", + grpc: { + endpoints: [{ address: "grpc://cas-mirror:50051" }], + store_type: "cas", + // Inherits zstd from the process-wide intent. + }, + }, +], +``` + +#### Opting a store out + +The upstream instance must accept zstd. When it does not — an older +NativeLink or a third-party cache without `compressed-blobs` support — or +when compression is undesirable for a particular link, opt that store out +explicitly: + +```json5 +stores: [ + { + name: "UNCOMPRESSED_UPSTREAM", + grpc: { + // ... + store_type: "cas", + experimental_remote_cache_compression: false, + }, + }, +], +``` + +NativeLink logs a startup warning for an eligible CAS gRPC store that opts +out while zstd is enabled elsewhere. Action-cache gRPC stores are never +eligible for REAPI blob wire compression: they're left out of inheritance, +and setting `experimental_remote_cache_compression: true` on one logs a +warning because the setting has no effect there. + +## Semantics worth knowing + +- Resource names and digests always refer to the **uncompressed** blob; + only the bytes on the wire are compressed. ByteStream compressed writes + report `committed_size` in compressed wire bytes, as the REAPI extension + specifies. +- Uploads are verified: NativeLink hashes the *decoded* bytes and rejects + a blob whose decompressed content doesn't match the digest or size it + was addressed with, bounding decompression by the expected size. +- Batch reads fall back to identity when the zstd encoding would not be + smaller, so incompressible blobs don't pay the CPU and size overhead. + +## When it helps, and when it doesn't + +Compression pays off when clients reach the cache across a real network +and the artifacts are compressible: uncompressed archives, binaries with +debug info, and text-heavy outputs commonly shrink 2-10x on the wire. It +does little on same-rack links — the zstd CPU cost buys nothing when the +wire isn't the bottleneck — and nothing for already-compressed artifacts. + +Wire compression doesn't change what's stored: the CAS holds raw bytes. +To also shrink bytes at rest, wrap the backing store in a +[`compression` store](/reference/nativelink-config/main#compressionspec); +the two compose, since one covers the wire and the other covers storage. + +## FAQ + + + + Yes. Clients only compress when the server advertises support, so + anything that doesn't request `compressed-blobs/zstd` keeps using + identity transfers against the same instance. + + + Yes, but order matters at the store level: deduplication must operate + on raw content — identical chunks stop being identical after + compression, so a `dedup` store fed compressed bytes finds no + duplicates. Wire compression is fine either way; it's undone at the + gRPC boundary before any store sees the bytes. + + diff --git a/web/apps/docs/content/docs/configuration/intro.mdx b/web/apps/docs/content/docs/configuration/intro.mdx index 75fde30dd..058d2c60c 100644 --- a/web/apps/docs/content/docs/configuration/intro.mdx +++ b/web/apps/docs/content/docs/configuration/intro.mdx @@ -160,6 +160,29 @@ autogenerated from the Rust source — every knob, every default, every constraint. Use this page for understanding, the reference for lookups. +## FAQ + + + + One file per cluster is the simplest way to start, and everything on + this page assumes it. Production deployments usually split into one + config per service — separate CAS, scheduler, and worker files — so + each service can be scaled, restarted, and deployed independently. + + + An in-memory CAS + AC behind one listener — + [`basic_cas.json5`](https://github.com/TraceMachina/nativelink/blob/main/nativelink-config/examples/basic_cas.json5) + in the repo. Fine for a demo, gone on restart; see + [Basic configurations](/configuration/basic) for shapes that survive + a reboot. + + + No — both sections are optional and only required on nodes that + accept `Execute()` calls or run actions. A cache-only node is just + `stores` and `servers`. + + + ## What's next - [Basic configurations](/configuration/basic) — runnable shapes diff --git a/web/apps/docs/content/docs/configuration/meta.json b/web/apps/docs/content/docs/configuration/meta.json index 3f037a30c..f7e7747cd 100644 --- a/web/apps/docs/content/docs/configuration/meta.json +++ b/web/apps/docs/content/docs/configuration/meta.json @@ -2,7 +2,9 @@ "pages": [ "intro", "basic", - "production" + "production", + "chunking", + "compression" ], "title": "Configuring NativeLink" } diff --git a/web/apps/docs/content/docs/configuration/production.mdx b/web/apps/docs/content/docs/configuration/production.mdx index f5f7e2f0b..4e81f2b4d 100644 --- a/web/apps/docs/content/docs/configuration/production.mdx +++ b/web/apps/docs/content/docs/configuration/production.mdx @@ -155,6 +155,55 @@ alarm) can read NativeLink's Prometheus output and scale accordingly. The [Kubernetes deployment guide](/deployment/kubernetes) has a working HPA config. +## Filesystem store: page-cache eviction + +The `filesystem` store has an opt-in `evict_page_cache` flag (default +`false`). When enabled, after every blob it writes or reads it asks the +kernel to drop that file's pages from the page cache +(`posix_fadvise(POSIX_FADV_DONTNEED)`). + +Most production deployments should leave it **off**. The common +enterprise topology (an object store with multiple CAS nodes) never +benefits from it, and enabling it carries two costs. + +```json5 +stores: [{ + filesystem: { + content_path: "/var/lib/nativelink/cas", + // Leave this off unless the narrow case below applies. + evict_page_cache: false, + }, +}], +``` + + + On a real filesystem (xfs/ext4), `POSIX_FADV_DONTNEED` takes the + kernel's `lru_add_drain_all()` path: it schedules and waits on a drain + across **every online CPU**, and concurrent callers serialize on a + global lock. The per-call cost therefore grows with the number of + cores, and **adding workers or concurrent actions cannot overcome + it**: every caller converges on the same serialized kernel path, so + throughput is capped no matter how much parallelism you add. On a + many-core host this + turns a busy store into a bottleneck while CPU and disk sit near idle. + (On `tmpfs` the call is a no-op, so this cost is invisible in + tmpfs-backed tests.) + + +The second cost: it evicts the page cache. A store kept on a fast local +disk that relies on the page cache as its hot read tier loses that cache +after every read and write. + +**When to enable it:** only for a filesystem-backed store on a low-core +host where keeping this store's I/O out of the page cache is specifically +desired (for example, to bound page-cache growth on a co-located +filesystem-only deployment). It was originally added to relieve page-cache +pressure that contributed to worker OOM-kills on such a deployment; note +that page cache is reclaimable and the dominant OOM driver is a worker's +anonymous memory (action processes and allocator retention), so this flag +is a narrow mitigation, not a general OOM fix. Do **not** enable it on +many-core hosts or object-store / multi-CAS deployments. + ## TLS and authentication In production, every hop runs over mTLS: @@ -210,6 +259,48 @@ What's worth alerting on: The [Metrics deployment guide](/deployment/metrics) has a Grafana dashboard JSON file you can import. +## Sandboxing + +We've seen in some client configurations issues where Bazel in particular can leave zombie processes around on workers. +To solve this, we've two options around sandboxing that are currently switched off by default for backwards +compatibility, but are recommended for production configurations + +```json5 +workers: [{ + local: { + use_namespaces: true, + use_mount_namespace: true + // rest of your config + } +}] +``` + +`use_namespaces` enables process namespacing for workers, and `use_mount_namespace` then also isolates the worker +root in a new mount namespace. Note, `use_mount_namespace` only works if `use_namespaces` is switched on as well. + +## FAQ + + + + The queue lives in scheduler memory and is restored from the Action + Cache on restart — which is why running two or three stateless + schedulers behind a load balancer is enough for HA. + + + Tag the workers (`gpu: { values: ["nvidia-a100"] }`) and declare the + property as `"exact"` in the scheduler's + `supported_platform_properties`. An action requesting that value is + only ever dispatched to matching workers. + + + No — it never verifies that an object in `fast` also exists in + `slow`. For artifacts that must survive a fast-tier wipe — remote + execution outputs especially — make sure the write path covers both + tiers deliberately. More store gotchas: + [Store overview](/reference/nativelink-config/store-overview#faq). + + + ## A reference production config A working complete production config (CAS + AC + scheduler + workers, diff --git a/web/apps/docs/content/docs/contribute/bazel.mdx b/web/apps/docs/content/docs/contribute/bazel.mdx index f8b9624c2..59c1eb42b 100644 --- a/web/apps/docs/content/docs/contribute/bazel.mdx +++ b/web/apps/docs/content/docs/contribute/bazel.mdx @@ -76,6 +76,21 @@ editor of choice will pick up. reuse Bazel's local cache; pointing at a remote NativeLink cluster makes a fresh clone fast for everyone. -For non-Bazel workflows, see -[Develop with Cargo](/contribute/cargo) or -[Develop with Nix](/contribute/nix). +## FAQ + + + + It bootstraps the toolchain and builds every dependency from source. + Subsequent builds are seconds — and pointing `--remote_cache` at a + NativeLink cluster (above) makes even a fresh clone fast. + + + No — target what you touched + (`bazel test //nativelink-store/tests:s3_store_test`), then run the + full `bazel test //...` once before submitting. + + For non-Bazel workflows, see + [Develop with Cargo](/contribute/cargo) or + [Develop with Nix](/contribute/nix). + + diff --git a/web/apps/docs/content/docs/contribute/cargo.mdx b/web/apps/docs/content/docs/contribute/cargo.mdx index a50a2053c..611846937 100644 --- a/web/apps/docs/content/docs/contribute/cargo.mdx +++ b/web/apps/docs/content/docs/contribute/cargo.mdx @@ -81,3 +81,17 @@ A few flags that help: For the Bazel-based workflow, see [Develop with Bazel](/contribute/bazel). + +## FAQ + + + + Not for most crates — the whole workspace builds with plain Cargo. + You need Bazel for the Bazel-only crates and for a pre-submit + `bazel test //...`, since that's what CI runs. + + + The gRPC services are generated from protobuf definitions at build + time; without `protoc` 3+ on `$PATH`, those generation steps fail. + + diff --git a/web/apps/docs/content/docs/contribute/docs.mdx b/web/apps/docs/content/docs/contribute/docs.mdx index 2f1164a38..c2788831e 100644 --- a/web/apps/docs/content/docs/contribute/docs.mdx +++ b/web/apps/docs/content/docs/contribute/docs.mdx @@ -101,3 +101,20 @@ For tabbed content, use Fumadocs's `Tabs` and `Tab`: Same flow as any other change — see [Contribution guidelines](/contribute/guidelines). Small docs PRs land same-day in most cases. + +## FAQ + + + + At the bottom of the page they belong to — each page ends with a + `## FAQ` section holding the questions readers actually ask about + that material. Add new Q&As there rather than to a standalone FAQ + section; there isn't one. + + + The same pre-commit suite as any PR, including + [Vale](https://vale.sh) style linting and typo checks over the MDX. + Run `pre-commit run --files ` locally to catch + failures before CI does. + + diff --git a/web/apps/docs/content/docs/contribute/guidelines.mdx b/web/apps/docs/content/docs/contribute/guidelines.mdx index fa799c18d..a55605077 100644 --- a/web/apps/docs/content/docs/contribute/guidelines.mdx +++ b/web/apps/docs/content/docs/contribute/guidelines.mdx @@ -63,7 +63,7 @@ We try to make the process predictable. - **First response within 2 business days.** If it's longer, ping us in the PR. -- **Two reviewers for non-trivial changes.** One for typo fixes. +- **One reviewer per change.** Others sometimes chime in. - **Squash on merge.** Every merged PR is one commit on `main`. ## License @@ -79,6 +79,22 @@ Meaningful contributors may be eligible for license waivers for Business Source License modules. Open an issue or contact the maintainers before depending on a waiver. +## FAQ + + + + [Cargo](/contribute/cargo) for small, localized changes — it's the + fastest way in. [Bazel](/contribute/bazel) when you want exactly what + CI runs. [Nix](/contribute/nix) for the fully-pinned shell, and + required for LRE work. + + + CI runs Bazel, and some crates are Bazel-only (the LRE flake outputs, + the Bazel-generated proto bindings). Run `bazel test //...` before + submitting if you touched anything Bazel-specific. + + + ## What's next Pick the dev environment that fits how you work: diff --git a/web/apps/docs/content/docs/contribute/nix.mdx b/web/apps/docs/content/docs/contribute/nix.mdx index 533b6b4de..3a84fc4d7 100644 --- a/web/apps/docs/content/docs/contribute/nix.mdx +++ b/web/apps/docs/content/docs/contribute/nix.mdx @@ -22,6 +22,18 @@ curl --proto '=https' --tlsv1.2 -sSf \ It enables flakes by default. + + - **Environment Paths**: If your shell doesn't recognize `nix` commands immediately after installation, you need to restart your terminal or run: + ```bash + . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh + ``` + - **Experimental Features**: If you used the standard Nix installer and get `experimental Nix feature 'nix-command' is disabled`, enable them by adding the following to your `~/.config/nix/nix.conf` file: + ```text + experimental-features = nix-command flakes + ``` + - **Disk Space**: Unpacking toolchains, compiler binaries, and caching build artifacts requires considerable storage. Ensure you have at least **15–20 GB of free space** on your drive before running `nix develop`. + + ## Enter the dev shell ```bash @@ -70,3 +82,19 @@ If you're making a small, localised change — typo fix, doc tweak, a unit test — the Cargo workflow is faster to get into. Nix shines for work touching the build graph, the LRE flow, or anything that needs exact toolchain reproducibility. + +## FAQ + + + + A package manager that builds every package in isolation and + addresses the result by a hash of all its inputs — which is why two + machines running `nix develop` on this repo get bit-identical + toolchains. + + + Only for [LRE](/explanations/lre) work. For everything else it's the + most reproducible option, not the mandatory one — the Cargo and Bazel + workflows stand on their own. + + diff --git a/web/apps/docs/content/docs/deployment/chromium.mdx b/web/apps/docs/content/docs/deployment/chromium.mdx index 98866327e..6c1a0a75a 100644 --- a/web/apps/docs/content/docs/deployment/chromium.mdx +++ b/web/apps/docs/content/docs/deployment/chromium.mdx @@ -1,11 +1,11 @@ --- title: Chromium -description: Building Chromium with NativeLink as the Reclient backend — a worked example for the largest public consumer. +description: Building Chromium with NativeLink as the Siso backend — a worked example for the largest public consumer. --- Chromium's build system shells out to -[Reclient](https://github.com/bazelbuild/reclient), which speaks the -Remote Execution API. Pointing it at a NativeLink cluster is a +[Siso](https://chromium.googlesource.com/build/+/refs/heads/main/siso/README.md), +which speaks the Remote Execution API. Pointing it at a NativeLink cluster is a configuration change — no patches to the Chromium tree. The Samsung Internet team runs this configuration in production for @@ -16,19 +16,17 @@ any Chromium-based browser. - A NativeLink cluster reachable from your build machines. Cache-only is fine to start; remote execution drops build times further. -- Reclient installed and on `$PATH`. Chromium's `gclient sync` will - install it under `buildtools/`. +- A Chromium checkout with `depot_tools` on `$PATH`. - The Chromium source checkout (`fetch chromium`). -## Configure Reclient +## Configure Siso -Reclient reads its server settings from environment variables. Add +Siso reads its server settings from environment variables. Add to your build shell: ```bash -export RBE_service=cas.nativelink.internal:50051 -export RBE_instance=chromium -export RBE_use_application_default_credentials=false +export SISO_REAPI_ADDRESS=cas.nativelink.internal:50051 +export SISO_REAPI_INSTANCE=chromium export RBE_service_no_security=false # mTLS in production export RBE_tls_client_auth_cert=/etc/nativelink/tls/client.crt export RBE_tls_client_auth_key=/etc/nativelink/tls/client.key @@ -38,8 +36,8 @@ export RBE_tls_ca_cert=/etc/nativelink/tls/ca.crt For local development against a non-TLS NativeLink: ```bash -export RBE_service=localhost:50051 -export RBE_instance=chromium +export SISO_REAPI_ADDRESS=localhost:50051 +export SISO_REAPI_INSTANCE=chromium export RBE_service_no_security=true ``` @@ -51,25 +49,12 @@ In your Chromium checkout: gn gen out/Default --args=' use_remoteexec=true use_goma=false - use_siso=false - reclient_cfg_dir="../../buildtools/reclient_cfgs/chromium-browser-clang" + use_siso=true ' ``` -The `use_remoteexec=true` flag is the one that matters — it tells the -build to wrap every compile invocation with Reclient. - -## Start the reproxy daemon - -Reclient uses a long-lived daemon (`reproxy`) that batches requests -to the RE-API server. Start it before invoking the build: - -```bash -buildtools/reclient/bootstrap --re_proxy=buildtools/reclient/reproxy -``` - -The daemon stays up; `bootstrap --shutdown` shuts it down when -you're done. +`autoninja` reads `args.gn`; with `use_siso=true`, it invokes +`siso ninja` for the build. ## Build @@ -83,16 +68,8 @@ of the time. ## What good looks like -The Reclient stats endpoint reports cache statistics per build: - -```bash -buildtools/reclient/reclient stats -``` - -Healthy numbers on warm builds: - - **Cache hit rate**: 85-95% on incremental builds; 60-80% on full - builds. + builds, visible from NativeLink cache metrics. - **Local fallback rate**: under 1%. Higher means workers are rejecting actions (platform mismatch, capacity). - **Network errors**: zero. Anything else is a problem. @@ -107,19 +84,34 @@ config should advertise: - `cpu_count: 8` (minimum; 16+ recommended for link steps) The -[`deployment-examples/chromium/`](https://github.com/TraceMachina/nativelink/tree/main/deployment-examples/chromium) +[`deploy/chromium-example/`](https://github.com/TraceMachina/nativelink/tree/main/deploy/chromium-example) directory in the source tree has the worker config Samsung uses. ## Troubleshooting - **All actions falling back to local.** Likely a platform-property - mismatch. Compare what Chromium is requesting (in the reclient + mismatch. Compare what Chromium is requesting (in the siso log) against what your workers advertise. +- **Siso is not being selected.** If the output directory was already + generated for Ninja, run `gn clean out/Default`, regenerate with + `use_siso=true`, and build again. - **Cache writes succeed, reads always miss.** Almost always a toolchain version mismatch between the action that wrote the cache and the one trying to read. -- **Reproxy hangs on shutdown.** Known issue — `reclient_cleanup` - fixes it. + +## FAQ + + + + No — pointing Siso at NativeLink is configuration only: GN args plus + the Siso environment variables. The same applies to Chromium forks; + Samsung Internet runs this pattern in production. + + + Yes. A cache-only cluster already cuts incremental build times; add + remote execution later for the full win on link-heavy full builds. + + ## What's next diff --git a/web/apps/docs/content/docs/deployment/kubernetes.mdx b/web/apps/docs/content/docs/deployment/kubernetes.mdx index 7933ab46d..f4b6efc40 100644 --- a/web/apps/docs/content/docs/deployment/kubernetes.mdx +++ b/web/apps/docs/content/docs/deployment/kubernetes.mdx @@ -41,7 +41,7 @@ spec: spec: containers: - name: nativelink - image: ghcr.io/tracemachina/nativelink:v1.4.0 + image: ghcr.io/tracemachina/nativelink:v1.6.1 args: ["/config/cas.json5"] ports: - containerPort: 50051 @@ -104,7 +104,7 @@ spec: spec: containers: - name: nativelink - image: ghcr.io/tracemachina/nativelink:v1.4.0 + image: ghcr.io/tracemachina/nativelink:v1.6.1 args: ["/config/worker.json5"] resources: requests: { cpu: 4, memory: 8Gi } @@ -172,6 +172,26 @@ directory in the source tree has: Clone the repo, point at your cluster, `helm install`. Tune from there. +## FAQ + + + + Yes — one binary can serve CAS, AC, scheduler, and worker from a + single config. Split into the three workloads above once you need to + scale or restart them independently. + + + The CAS owns persistent volumes and a stable identity per replica — + losing one loses cached blobs. Workers hold no state at all; kill and + reschedule them freely, which is exactly what the HPA does. + + + Yes. Every RE-API service is gRPC; an Ingress that downgrades to + plain HTTP/1.1 breaks the protocol. NGINX needs `grpc_pass`; any + modern Gateway API implementation handles it. + + + ## What's next - [Metrics](/deployment/metrics) — wire it into your Grafana. diff --git a/web/apps/docs/content/docs/deployment/meta.json b/web/apps/docs/content/docs/deployment/meta.json index 7c04eb918..820895be8 100644 --- a/web/apps/docs/content/docs/deployment/meta.json +++ b/web/apps/docs/content/docs/deployment/meta.json @@ -2,6 +2,7 @@ "pages": [ "on-prem-overview", "kubernetes", + "oci-object-storage", "chromium", "metrics", "persistent-workers" diff --git a/web/apps/docs/content/docs/deployment/metrics.mdx b/web/apps/docs/content/docs/deployment/metrics.mdx index 3b15536f4..8e8b3bdc4 100644 --- a/web/apps/docs/content/docs/deployment/metrics.mdx +++ b/web/apps/docs/content/docs/deployment/metrics.mdx @@ -11,7 +11,7 @@ metrics are available when the store is explicitly wrapped with the opt-in NativeLink metrics are licensed under the Business Source License. Individual developer cache use does not need a commercial license. Teams using metrics in shared, production, or commercial settings -can use NativeLink Cloud, Enterprise, or an intentionally +can use NativeLink Enterprise or an intentionally very inexpensive separate license. See the [license page](https://nativelink.com/license). @@ -168,19 +168,28 @@ results include `hit`, `miss`, `expired`, `success`, and `error`. ### Execution metrics +Base labels below are `execution_instance`, `execution_worker_id` (when a worker +is known), and `execution_priority`. + | Metric | Type | Description | Labels | | ------ | ---- | ----------- | ------ | -| `nativelink_execution_stage_duration` | Histogram | Time spent in each execution stage | `execution_stage` | -| `nativelink_execution_total_duration` | Histogram | Total execution time from submission to completion | `execution_instance` | -| `nativelink_execution_queue_time` | Histogram | Time spent waiting in queue | `execution_priority` | +| `nativelink_execution_stage_duration` | Histogram | Time spent in each worker phase, in seconds | base + `execution_stage` (phase) | +| `nativelink_execution_total_duration` | Histogram | End-to-end time from queued to worker completion, in seconds | base | +| `nativelink_execution_queue_time` | Histogram | Time waiting in queue before a worker started, in seconds | base | | `nativelink_execution_active_count` | Gauge | Current actions in each stage | `execution_stage` | | `nativelink_execution_completed_count_total` | Counter | Completed executions | `execution_result`, `execution_action_digest` | | `nativelink_execution_stage_transitions_total` | Counter | Stage transition events | `execution_instance`, `execution_priority` | -| `nativelink_execution_output_size` | Histogram | Size of execution outputs | - | -| `nativelink_execution_retry_count_total` | Counter | Number of retries | - | +| `nativelink_execution_output_size` | Histogram | Total output bytes (output files plus stdout/stderr) | base | +| `nativelink_execution_retry_count_total` | Counter | Execution retries (a failed attempt that re-queued the action) | base | + +The `execution_stage` label differs by metric. For `nativelink_execution_active_count` +and `nativelink_execution_stage_transitions_total` it is one of `unknown`, +`cache_check`, `queued`, `executing`, or `completed`. For +`nativelink_execution_stage_duration` it is the worker phase: `input_fetch`, +`execution`, or `output_upload`. -Execution stages are `unknown`, `cache_check`, `queued`, `executing`, and -`completed`. +The histograms and `nativelink_execution_retry_count_total` are populated once an +action runs on a worker; cache hits do not emit them. Counter metrics are exposed with a `_total` suffix in Prometheus. The Docker Compose quickstart, recording rules, and included dashboards assume `_total` @@ -270,6 +279,30 @@ storage: out_of_order_time_window: 1h ``` +## FAQ + + + + No — NativeLink emits OTLP only; there is no scrape endpoint. Either + run an OpenTelemetry Collector and let Prometheus scrape the + Collector's exporter, or enable Prometheus's OTLP receiver + (`--web.enable-otlp-receiver`) and send straight to it. The + [quick start](#quick-start) wires up the first path. + + + Metrics are one of the few Business Source License modules. + Individual developer use is fine; shared, production, or commercial + settings need NativeLink Enterprise or an intentionally + inexpensive commercial license — see the + [license page](https://nativelink.com/license). + + + `nativelink_scheduler_queue_depth` — the signal the + [Kubernetes HPA example](/deployment/kubernetes) targets. CPU-based + scaling reacts too slowly because workers are mostly I/O-bound. + + + ## Additional resources - [Metrics deployment examples](https://github.com/TraceMachina/nativelink/tree/main/deployment-examples/metrics) diff --git a/web/apps/docs/content/docs/deployment/oci-object-storage.mdx b/web/apps/docs/content/docs/deployment/oci-object-storage.mdx new file mode 100644 index 000000000..380709535 --- /dev/null +++ b/web/apps/docs/content/docs/deployment/oci-object-storage.mdx @@ -0,0 +1,153 @@ +--- +title: Oracle Cloud (OCI) Object Storage +description: Back NativeLink's CAS and Action Cache with Oracle Cloud Infrastructure Object Storage via its S3 Compatibility API. +--- + +NativeLink can use [Oracle Cloud Infrastructure (OCI) Object +Storage](https://www.oracle.com/cloud/storage/object-storage/) as the backing +store for the CAS and Action Cache. It is configured through the +`experimental_cloud_object_store` store with `provider: "oci"`, alongside the +`aws`, `gcs`, `azure`, and `r2` providers. + +## How it works + +OCI Object Storage exposes an [S3 Compatibility +API](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm). +The OCI store is a thin adapter that points NativeLink's S3 store +at OCI's S3-compatible endpoint, so it reuses the same multipart upload, retry, +and streaming code paths as the AWS backend. Two OCI-specific adjustments are +applied automatically: + +- **Path-style addressing** - OCI requires `endpoint/bucket/key` rather than + virtual-hosted (`bucket.endpoint/key`) URLs. +- **Checksums downgraded to "when required"** - the AWS SDK otherwise adds a + default trailing checksum that forces `Content-Encoding: aws-chunked`, which + OCI rejects with `501 NotImplemented: AWS chunked encoding not supported`. + Without this, small single-`PUT` objects (notably Action Cache entries) fail. + +You do not need to configure either of these; they are handled by the store. + +## Prerequisites + +1. **A bucket.** Create one in the OCI Console under *Storage → Buckets*, or + with `oci os bucket create`. Note the bucket's **region** (e.g. + `ap-mumbai-1`). +2. **Your Object Storage namespace.** A tenancy-wide identifier shown under + *Tenancy details*, or via `oci os ns get`. The endpoint is derived as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. +3. **A Customer Secret Key** (see [Authentication](#authentication)). + +## Authentication + +OCI's S3 Compatibility API authenticates with **Customer Secret Keys** - a +static access-key / secret-key pair, used as the S3 `access_key_id` and +`secret_access_key`. + +Generate one in the Console under *Profile → Customer Secret Keys → Generate +Secret Key*: + +- The **Secret Key** is shown **only once** at generation time - copy it + immediately. +- The **Access Key** is listed permanently in the Customer Secret Keys table and + can be copied at any time. + +Grant the associated user read/write on the bucket with a least-privilege +policy: + +``` +Allow group to manage object-family in compartment where target.bucket.name='' +``` + +We recommend supplying the keys via environment variables and referencing them +with shellexpand. + + + The S3 Compatibility API supports **only** Customer Secret Keys. OCI-native + authentication - API signing keys, and instance/resource principals - is **not** + available through this store. If you run NativeLink on OCI compute and want + keyless workload-identity auth, that is not currently supported; you must use + static Customer Secret Keys and rotate them yourself. + + +## Configuration + +A minimal CAS + Action Cache setup (see also +[`oci_backend.json5`](https://github.com/TraceMachina/nativelink/blob/main/nativelink-config/examples/oci_backend.json5)): + +```json5 +{ + stores: [ + { + name: "CAS_MAIN_STORE", + experimental_cloud_object_store: { + provider: "oci", + namespace: "storagenamespace", + region: "ap-mumbai-1", + bucket: "nativelink-cas", + access_key_id: "${OCI_ACCESS_KEY_ID}", + secret_access_key: "${OCI_SECRET_ACCESS_KEY}", + key_prefix: "cas/", + retry: { max_retries: 6, delay: 0.3, jitter: 0.5 }, + }, + }, + { + name: "AC_MAIN_STORE", + experimental_cloud_object_store: { + provider: "oci", + namespace: "storagenamespace", + region: "ap-mumbai-1", + bucket: "nativelink-cas", + access_key_id: "${OCI_ACCESS_KEY_ID}", + secret_access_key: "${OCI_SECRET_ACCESS_KEY}", + key_prefix: "ac/", + retry: { max_retries: 6, delay: 0.3, jitter: 0.5 }, + }, + }, + ], + // ...servers omitted; see oci_backend.json5 +} +``` + +In production, wrap the CAS store in `verify` (for integrity) and front it with +a `fast_slow` filesystem/memory layer to cut round-trips to OCI, exactly as you +would for the AWS backend. + +### Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `namespace` | yes | Object Storage namespace; used to derive the endpoint. | +| `region` | yes | OCI region id (e.g. `ap-mumbai-1`); also the SigV4 signing region. | +| `bucket` | yes | Target bucket. | +| `access_key_id` | no | Customer Secret Key access key. Falls back to the AWS default credential chain if unset. | +| `secret_access_key` | no | Customer Secret Key secret. | +| `key_prefix`, `retry`, ... | no | Shared `experimental_cloud_object_store` options. | + +## Operational notes + +- **Reap incomplete multipart uploads.** When a multipart upload fails + mid-flight the store issues `AbortMultipartUpload` to clean up (verified that + OCI honors both `ListMultipartUploads` and `AbortMultipartUpload`). A process + killed *before* it can abort still leaves orphaned parts, so add a bucket + lifecycle rule to abort incomplete multipart uploads after a few days as a + backstop. +- **Status.** This backend lives under `experimental_cloud_object_store`. Its + core paths - read, write, existence checks, ranged reads, multipart, and + integrity - are verified against live OCI, including an end-to-end Bazel remote + cache round-trip, a 2 GiB multipart upload (~400 parts) with full byte + verification, multipart abort/cleanup, and 200-way concurrent load. It has not + been benchmarked at sustained production scale or duration. + +## FAQ + + + + Yes — segment them with `key_prefix` (`cas/` and `ac/` in the example + above) rather than provisioning two buckets. + + + `aws`, `gcs`, `azure`, `ontap`, and `r2`, alongside `oci` — one store + type, six providers, sharing the same multipart, retry, and streaming + code paths. + + diff --git a/web/apps/docs/content/docs/deployment/on-prem-overview.mdx b/web/apps/docs/content/docs/deployment/on-prem-overview.mdx index 274c0e45b..d035b630d 100644 --- a/web/apps/docs/content/docs/deployment/on-prem-overview.mdx +++ b/web/apps/docs/content/docs/deployment/on-prem-overview.mdx @@ -107,7 +107,7 @@ contracts; truly global teams. Numbers we've seen in production. Yours will vary — these are the order-of-magnitude starting points: -| Resource | Per active developer / week | +| Resource | Per active developer | | --------------------- | ------------------------------- | | CAS storage (C++) | 15-20 GB | | CAS storage (Go/Rust) | 5-10 GB | @@ -118,6 +118,29 @@ order-of-magnitude starting points: When the cluster is healthy, the scheduler is the cheapest piece and CAS storage is the dominant cost. Plan accordingly. +## FAQ + + + + The CAS. Schedulers and workers are stateless, and the Action Cache + can be wiped harmlessly — losing it just forces re-execution until it + warms back up. That asymmetry drives backup policy: snapshot the CAS + backend, treat everything else as disposable. + + + On scheduler queue depth, not CPU — workers spend most of their time + blocked on I/O, so CPU-based scaling reacts too late. The + [Kubernetes guide](/deployment/kubernetes) has a working HPA + targeting `nativelink_scheduler_queue_depth`. + + + Filesystem CAS: `rsync` or ZFS/Btrfs snapshots. S3-compatible: + versioning, lifecycle policies, and cross-region replication for DR. + Redis: ephemeral by design — loss is a cache miss. The procedure is + in [NativeLink on-prem](/getting-started/on-prem). + + + ## What's next - [Kubernetes](/deployment/kubernetes) — working Helm chart. diff --git a/web/apps/docs/content/docs/deployment/persistent-workers.mdx b/web/apps/docs/content/docs/deployment/persistent-workers.mdx index 9ebdbddd0..a77c84043 100644 --- a/web/apps/docs/content/docs/deployment/persistent-workers.mdx +++ b/web/apps/docs/content/docs/deployment/persistent-workers.mdx @@ -15,7 +15,7 @@ cost is paid once; subsequent actions reuse the same process. Remote persistent workers are licensed under the Business Source License. Individual developer cache use does not need a commercial license. Teams using persistent workers in shared, production, or -commercial settings can use NativeLink Cloud, Enterprise, or an +commercial settings can use NativeLink Enterprise or an intentionally very inexpensive separate license. See the [license page](https://nativelink.com/license). @@ -110,6 +110,22 @@ clusters don't waste memory. a soft mitigation; for serious workloads, set a hard `max_invocations` and recycle. +## FAQ + + + + Rarely — plain `clang` starts in ~10 ms, so the win is negligible and + not worth the caveats. They pay back almost immediately on JVM-family + toolchains (`javac`, `kotlinc`) and modestly on `rustc`. + + + They can — a warm process isn't sandboxed by default, so a toolchain + that mutates global state between invocations produces + nondeterministic results. Sandbox the worker process itself and + recycle workers periodically (see [Caveats](#caveats)). + + + ## What's next - [Configuration → Production](/configuration/production) — the diff --git a/web/apps/docs/content/docs/explanations/architecture.mdx b/web/apps/docs/content/docs/explanations/architecture.mdx index b2ec97080..e416e061e 100644 --- a/web/apps/docs/content/docs/explanations/architecture.mdx +++ b/web/apps/docs/content/docs/explanations/architecture.mdx @@ -11,7 +11,7 @@ real clusters run them together. ## The four roles {`sequenceDiagram - participant client as Client (Bazel / Buck2 / Reclient) + participant client as Client (Bazel / Buck2 / Siso) participant sched as Scheduler participant worker as Worker participant cas as CAS + AC @@ -140,6 +140,28 @@ Three operational properties drove the design: The same simplicity at the protocol level is why NativeLink can sustain over a billion build requests a month on modest hardware. +## FAQ + + + + Only the CAS — losing it loses every cached artifact. The AC is a + lookup table you can lose harmlessly: clients re-execute and refill + it. Schedulers and workers hold no durable state at all. + + + Yes — the same executable serves any subset, chosen by config. + Single-developer setups run everything in one process; teams split + the services so each scales independently. + + + A namespace within one cluster: action hashes from different instance + names never collide, so one deployment can serve isolated teams. + Every client and server must agree on it — a mismatch looks like a + permanently empty cache. More vocabulary in the + [glossary](/reference/glossary). + + + ## What's next - [Local Remote Execution](/explanations/lre) — running the same diff --git a/web/apps/docs/content/docs/explanations/history.mdx b/web/apps/docs/content/docs/explanations/history.mdx index 3631ac4d2..8659694fc 100644 --- a/web/apps/docs/content/docs/explanations/history.mdx +++ b/web/apps/docs/content/docs/explanations/history.mdx @@ -70,3 +70,22 @@ working examples, a clear path from `setup` to `production`. If you find a gap, the docs source lives in [`web/apps/docs/content/docs`](https://github.com/TraceMachina/nativelink) and PRs are welcome. + +## FAQ + + + + Three operational reasons: no GC pauses (tail latency comes from + network and storage, not the runtime), memory safety (a scheduler + memory bug could silently serve a wrong artifact org-wide — Rust + removes the class at compile time), and throughput (a single instance + sustains over a billion requests a month with sub-millisecond `p99` + lookups). + + + Compile times — mitigated by sccache backed by NativeLink itself — + and a smaller hiring pool, which has hurt less than expected: the + people who write distributed-systems Rust tend to be exactly the + people you want writing distributed systems. + + diff --git a/web/apps/docs/content/docs/explanations/lre.mdx b/web/apps/docs/content/docs/explanations/lre.mdx index 295868e8f..23f7b5761 100644 --- a/web/apps/docs/content/docs/explanations/lre.mdx +++ b/web/apps/docs/content/docs/explanations/lre.mdx @@ -66,39 +66,62 @@ The recommended flow: is the easiest path.
  • - **Pull the NativeLink LRE flake template.** + **Pull the NativeLink Bazel flake template.** ```bash - nix flake init -t github:TraceMachina/nativelink#lre + nix flake init -t github:TraceMachina/nativelink#bazel ```
  • - **Enter the dev shell.** This downloads the pinned toolchain on - first run. + **Enter the dev shell.** This downloads the Nix-pinned toolchain on + first run and generates `lre.bazelrc`, which the template's + `.bazelrc` already `try-import`s. ```bash nix develop ```
  • - **Start the local worker.** The template ships with a - `nativelink-lre.json5` that binds CAS, AC, scheduler, and a single - worker to `localhost:50051`. + **Point `user.bazelrc` at a NativeLink cache and executor.** The + template ships it with placeholders: ```bash - nativelink ./nativelink-lre.json5 + build --remote_cache=grpcs://TODO + build --bes_backend=grpcs://TODO + build --remote_timeout=600 + build --remote_executor=grpcs://TODO ``` + + Fill these in with a self-hosted cluster that has a worker capable + of the platform the example needs. A plain + [local instance](/rbe/local-testing) (drop the `s` in `grpcs://`, + point at `127.0.0.1`) is enough to validate `remote_cache`, but + the C++ example's `lre-cc` platform still needs a real worker + running the matching container image — see + [Local Remote Execution](/rbe/local-remote-execution) for the + exact commands and what each one actually requires.
  • - **Point your build system at it.** The flake includes a - `.bazelrc.lre` that's pre-configured; for non-Bazel clients see - [Getting Started → Other build systems](/getting-started/other-build-systems). + **Build the example.** + + ```bash + bazel build hello-world + ```
  • The first build will be the same wall-time as a normal local build. The second one will be near-instant — that's the cache doing its job. + + The template above is the fastest way to see LRE working, but it + starts a new project. To add the same Nix-pinned toolchains to a + project you already have, see the full flake-side and Bazel-side + wiring — the `nativelink.flakeModule` import, `lre.installationScript`, + and the `local-remote-execution` Bazel module override — in + [`local-remote-execution/README.md`](https://github.com/TraceMachina/nativelink/blob/main/local-remote-execution/README.md). + + ## Why Nix, specifically? LRE needs every input to a build action to be hashable. The compiler, @@ -111,14 +134,47 @@ filesystem state. That's the entire reason. Nix gives us hash-pinned tools; everything else follows. -For background, see [What is Nix?](/faq/nix) and -[How do I make my Bazel setup hermetic?](/faq/hermeticity). +For background on Nix itself, see +[Develop with Nix](/contribute/nix); for the hermeticity checklist, +see the [FAQ](#faq) below. + +## FAQ + + + + Pin the toolchain (Nix or `rules_cc`'s toolchain abstraction — + never `/usr/bin/cc`), pin every `http_archive` URL and sha256, + add `build --incompatible_strict_action_env` to stop `$PATH` + leaks, enable strict include checking + (`--features=layering_check`), and compare action hashes across + machines with `bazel aquery`. LRE gives you the toolchain-pinning + piece for free. + + + Build the same target twice on the same machine under LRE and + compare outputs — anything that differs is a leak. At the cluster + level, non-hermetic actions surface as cache misses where you + expected hits, or as nondeterministic action results. + + + No — it solves determinism, not throughput. Fan-out across + hundreds of cores, or building for platforms you can't host, + still wants remote workers. The point is that action hashes + match, so local and remote execution share one cache. + + ## What's next +- [RBE → Local Remote Execution](/rbe/local-remote-execution) — the + Setup steps above, run for real, plus what's actually + local-vs-remote once you leave `x86_64-linux`. +- [Local cache and executor](/rbe/local-testing) — a cache and + executor to point the setup above at, no Nix required for the + server side. - [Architecture](/explanations/architecture) — the full RE-API picture LRE plugs into. - [Configuration → Basic](/configuration/basic) — the JSON5 the local worker reads. -- [RBE → Nix templates](/rbe/nix-templates) — runnable LRE - reference setups. +- [RBE → Nix templates](/rbe/nix-templates) — the `bazel` flake + template this page walks through. diff --git a/web/apps/docs/content/docs/faq/caching.mdx b/web/apps/docs/content/docs/faq/caching.mdx deleted file mode 100644 index 4c3a897e3..000000000 --- a/web/apps/docs/content/docs/faq/caching.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: What is remote caching? -description: Reuse build outputs across machines so you only pay for compilation once. ---- - -Remote caching is the practice of storing the result of every build -action in a shared store, keyed by the hash of the action's inputs. If -anyone has already compiled the file you're about to compile — a -teammate, your CI, an agent — you fetch the result instead of doing -the work. - -## How the hash gets computed - -Take everything that affects a compilation's output: - -- The source files (each by content hash). -- The compiler binary (by content hash). -- The compile command, exactly as it'll be executed. -- The set of header files included transitively. -- Anything else the build system declared as an input. - -Hash that whole bundle. Two invocations with the same bundle produce -identical outputs; the cache returns the prior result. One byte -different anywhere — a header you didn't realise you depended on, a -patch version bump in the compiler — and the hash changes, the cache -misses, the work runs fresh. - -This only works if the build is **hermetic** — i.e. every input is -declared. See [hermeticity](/faq/hermeticity). - -## What a cache hit looks like - -A typical Bazel hit: - -``` -INFO: From Compiling src/foo.cc: -(remote cache hit) -Target //src:foo up-to-date: - bazel-bin/src/libfoo.a -``` - -The action ran in 2-10 ms. The compiler never started; the linker -never touched it. You paid the cost of one HTTP request. - -## Where NativeLink fits - -NativeLink implements the standard -[Remote Execution API](https://github.com/bazelbuild/remote-apis) — -the same protocol Bazel, Buck2, Reclient, Goma, and Pants speak. You -point your build at a NativeLink server, and every action gets cached -automatically. - -The fast version: [Setup](/getting-started/setup). diff --git a/web/apps/docs/content/docs/faq/cost.mdx b/web/apps/docs/content/docs/faq/cost.mdx deleted file mode 100644 index d3b6dadc7..000000000 --- a/web/apps/docs/content/docs/faq/cost.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Is NativeLink free? -description: Yes — NativeLink is source-available and free for permitted self-hosted use. Cloud and Enterprise are paid offerings. ---- - -**Yes — NativeLink is source-available and free for permitted -self-hosted use.** Most of the monorepo is licensed under -`FSL-1.1-Apache-2.0`, which allows internal use, modification, and -redistribution for non-competing purposes, then grants an Apache 2.0 -future license on the schedule described in the repository -[`LICENSE`](https://github.com/TraceMachina/nativelink/blob/main/LICENSE). -The customer-facing summary lives on the -[NativeLink license page](https://nativelink.com/license). - -NativeLink is not a single-license monorepo. Some feature modules -carry their own source headers. In particular, metrics and remote -persistent workers are licensed under the Business Source License. -Developers using NativeLink for an individual cache do not need a -commercial license. Teams using those modules in shared, production, -or commercial settings can use NativeLink Cloud, Enterprise, or a -separate commercial license, which is intentionally very inexpensive. -Meaningful contributors may be eligible for license waivers; contact -the maintainers before relying on one. - -If you'd rather pay someone to run it for you, two paid tiers exist: - -- **Cloud** — managed multi-tenant cluster, flat $999+/month. Full - SLA, autoscaling, dashboard. -- **Enterprise** — single-tenant deployment, dedicated solutions - engineer, on-prem or managed. Custom contracts. - -The -[pricing page](https://nativelink.com/pricing) has the feature -comparison. - -## What does "free" actually cover - -- The full RE-API server: CAS, AC, scheduler, worker. -- Every storage backend: filesystem, S3, Redis, GCS, Azure Blob. -- Every supported build client: Bazel, Buck2, Reclient, Pants, Goma. -- The CLI tooling and Helm chart. - -No artificial limits on cache size, action count, worker count, or -team size. The self-hosted build is the same codebase we run in -production, subject to the license that applies to each module, minus -the operational tooling and dedicated support that Cloud and -Enterprise add. - -## What you'd pay for instead - -Hosting NativeLink yourself costs: - -- Compute for the control plane (typically a few small VMs). -- Storage for the CAS (S3 / equivalent, sized for ~5-20 GB per active - developer per week). -- Worker compute (variable; this is the part Cloud rents to you). -- Engineer hours running it. - -For most teams under 30 engineers, self-host is cheaper. Past that, -Cloud usually wins on engineer-time alone. diff --git a/web/apps/docs/content/docs/faq/hermeticity.mdx b/web/apps/docs/content/docs/faq/hermeticity.mdx deleted file mode 100644 index e9ae2844a..000000000 --- a/web/apps/docs/content/docs/faq/hermeticity.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: How do I make my Bazel setup hermetic? -description: Eliminate every "it works on my machine" by declaring every input. ---- - -A hermetic build is one where every input is declared, every output -is reproducible, and the result depends only on the declared inputs. -Same recipe, same ingredients, same dish, every time. - -Bazel **can** produce hermetic builds. Out of the box, it doesn't — -most Bazel projects depend implicitly on system tooling, environment -variables, and the host OS. Reaching real hermeticity takes -deliberate work. - -## The hermeticity checklist - - -
  • - **Pin the toolchain.** Don't rely on `/usr/bin/cc`. Use - `rules_cc`'s toolchain abstraction or a Nix-provided toolchain; - register the platform in `MODULE.bazel`. -
  • -
  • - **Lock dependency sources.** Every `http_archive` should pin both - the URL and the sha256. Module dependencies should pin a version, - not a range. -
  • -
  • - **Forbid `$PATH` leaks.** Add - `build --incompatible_strict_action_env` to your `.bazelrc`. - Bazel will now only forward an explicitly-allowed set of env - vars. -
  • -
  • - **Use the sandbox you trust.** On Linux: `linux-sandbox`. On - macOS: `darwin-sandbox`. For maximum isolation, run actions in a - container or under [LRE](/explanations/lre). -
  • -
  • - **Declare every header.** Strict include-checking - (`--features=layering_check`) catches the headers your `cc_library` - silently transitively depends on. -
  • -
  • - **Compare action hashes across machines.** If the same target - produces different hashes on two laptops, something is leaking. - `bazel aquery 'mnemonic("CppCompile", //target:label)' --output=text` - shows you the action's full input set. -
  • -
    - -## How NativeLink helps - -A hermetic build maps directly to a content-addressed cache: same -inputs = same hash = same cached result. NativeLink doesn't *make* -your build hermetic, but it surfaces failures fast — non-hermetic -actions show up as cache misses where there should be hits, or, worse, -as nondeterministic action results. - -The fastest way to find leaks: enable -[LRE](/explanations/lre), build the same target twice on the -same machine, and compare outputs. Anything that differs is a leak. - -## Further reading - -- [What are toolchains?](/faq/toolchains) -- [What is Nix?](/faq/nix) -- [LRE](/explanations/lre) — the easiest way to get there. diff --git a/web/apps/docs/content/docs/faq/lre.mdx b/web/apps/docs/content/docs/faq/lre.mdx deleted file mode 100644 index d781c04d5..000000000 --- a/web/apps/docs/content/docs/faq/lre.mdx +++ /dev/null @@ -1,48 +0,0 @@ ---- -title: What is LRE? -description: Local Remote Execution — the hermeticity of RBE without the network. ---- - -LRE (Local Remote Execution) runs a NativeLink worker on your laptop -and routes every build action through it. You get the hermeticity -guarantees of remote execution — content-addressed inputs, pinned -toolchain, sandboxed processes — without sending anything over the -network. - -## What it solves - -The classic developer-experience trade-off: - -- **Pure local build** — fast feedback, "works on my machine" bugs. -- **Pure remote build** — bit-identical with CI, slow on every change. - -LRE is the third option: bit-identical with CI, fast on every change. -Cache hits from the remote cluster apply locally; cache writes from -local apply remotely. - -## How it works - -Three pieces: - -1. A NativeLink server bound to `localhost`. -2. A Nix-pinned toolchain: every binary the build invokes has a - content-addressed path in the Nix store. -3. A configured build client (Bazel, Buck2, ...) targeting the local - server. - -The build issues the same `Execute` RPCs it would issue against a -remote cluster — they just happen to land on `localhost`. - -## When to use LRE - -| Scenario | LRE | -| ---------------------------------------------- | ---- | -| Solo dev iterating, want CI reproducibility | ✓ | -| Team sharing a cache without a server | ✓ | -| Repro a CI failure locally | ✓ | -| Fan-out across 200 cores | ✗ | -| Building for a platform you can't host | ✗ | - -The split: LRE for determinism, remote workers for throughput. - -The full write-up: [Explanations → LRE](/explanations/lre). diff --git a/web/apps/docs/content/docs/faq/meta.json b/web/apps/docs/content/docs/faq/meta.json deleted file mode 100644 index 22e2d0e38..000000000 --- a/web/apps/docs/content/docs/faq/meta.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "pages": [ - "cost", - "caching", - "remote-execution", - "lre", - "toolchains", - "hermeticity", - "nix", - "rust" - ], - "title": "FAQ" -} diff --git a/web/apps/docs/content/docs/faq/nix.mdx b/web/apps/docs/content/docs/faq/nix.mdx deleted file mode 100644 index 07c0b07ee..000000000 --- a/web/apps/docs/content/docs/faq/nix.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: What is Nix? -description: A purely functional package manager that gives NativeLink its hermeticity guarantees. ---- - -Nix is a package manager that builds every package in isolation, with -a hash that encodes every input — source code, dependencies, build -flags, even the version of `gcc` used to compile the dependencies. -Two machines running the same Nix flake produce bit-identical -artifacts. - -That property — hash-pinned, content-addressed everything — is what -NativeLink needs for [LRE](/explanations/lre) and is why we use -Nix to provision toolchains. - -## What it gives you, concretely - -- **Toolchains in the Nix store.** Your `clang` lives at - `/nix/store/abc123-clang-18.1.6/bin/clang`. The path itself is the - hash. NativeLink can use that path as an input identifier directly. -- **No "global" state to leak.** A Nix shell exposes only the - packages you ask for. There's no `/usr/lib` to accidentally - depend on. -- **Reproducible across machines.** `nix develop` on your laptop and - on CI produces the same shell, byte-for-byte. - -## What you give up - -- A learning curve. The Nix language is unfamiliar; the error - messages take getting used to. -- Initial download time. The first `nix develop` for a big project - fetches gigabytes. - -## How to start - -The -[next-gen Nix installer](https://github.com/NixOS/experimental-nix-installer) -is the smoothest path. After installing: - -```bash -git clone https://github.com/TraceMachina/nativelink -cd nativelink -nix develop -``` - -You're now in a shell with the exact toolchain CI uses — Rust, Bazel, -mold, `protoc`, the works. - -For a full LRE setup, see [Explanations → LRE](/explanations/lre). diff --git a/web/apps/docs/content/docs/faq/remote-execution.mdx b/web/apps/docs/content/docs/faq/remote-execution.mdx deleted file mode 100644 index 2719c2193..000000000 --- a/web/apps/docs/content/docs/faq/remote-execution.mdx +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: What is remote execution? -description: Build steps run on a worker fleet, not your laptop. Faster builds, lower bills. ---- - -Remote execution ships the build action — inputs, command, sandbox -spec — to a fleet of workers and brings back the outputs. Your laptop -or CI runner becomes a thin coordinator; the heavy lifting happens on -hardware sized for it. - -## The shape - -``` -[ client ] ─ Execute() ─▶ [ scheduler ] - │ - ┌───────┼───────┐ - ▼ ▼ ▼ - [worker] [worker] [worker] - │ │ │ - └───────┴───────┘ - ▼ - [ CAS / AC ] -``` - -The client tells the scheduler "run this action." The scheduler picks -a worker that satisfies the action's platform requirements. The -worker fetches inputs from the content-addressed store, runs the -command in a sandbox, uploads outputs back to the store, and reports -the result. - -The cache from [remote caching](/faq/caching) sits underneath -all of this — actions hit it first; only misses get executed. - -## Why ship the work elsewhere - -Three reasons, in roughly the order teams adopt them: - -1. **Throughput.** A worker fleet has more cores than any one - developer machine. Linker steps that take 60 seconds on a laptop - take 8 on a hot worker. -2. **Hermeticity.** The worker has exactly one job, in exactly one - environment. No conflicting versions of system libraries, no - stale `/tmp`, no surprises. -3. **Cost.** CI runners are expensive because they sit idle most of - the day. A worker fleet utilises hardware constantly — average - utilisation goes from 5-10% to 60-80%. - -## Where NativeLink fits - -NativeLink is a Remote Execution API server. Any build tool that -speaks the protocol — -[Bazel](https://bazel.build), -[Buck2](https://buck2.build), -[Reclient](https://github.com/bazelbuild/reclient), -[Pants](https://www.pantsbuild.org), -[Goma](https://chromium.googlesource.com/infra/goma/client/) — -plugs in with no code changes. - -The flow looks like the diagram above, with NativeLink as the -scheduler + worker fleet. See -[Architecture](/explanations/architecture) for the full -walkthrough. diff --git a/web/apps/docs/content/docs/faq/rust.mdx b/web/apps/docs/content/docs/faq/rust.mdx deleted file mode 100644 index d68b53da1..000000000 --- a/web/apps/docs/content/docs/faq/rust.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Why Rust? -description: Memory safety without garbage collection — the right shape for a service that has to be fast and never lie. ---- - -Three reasons: - -## No GC pauses - -Build infrastructure runs under sustained load. A scheduler hiccup -during a `p99` request is the difference between "the build felt -fast" and "the build was unpredictable." Garbage-collected runtimes -insert that hiccup at exactly the wrong time, sized roughly to the -heap. - -Rust has no garbage collector. The tail latency on a NativeLink -cluster comes from network and storage, not the language runtime. - -## Memory safety - -A miscompiled binary that ships across an organisation is a serious -problem. Worse, build systems are pure-function critical -infrastructure: a memory bug in the scheduler could silently produce -the wrong artifact and serve it from cache to every developer. - -Rust catches those bugs at compile time. The class of incident -involving "we shipped something that wasn't what we compiled" doesn't -happen. - -## Throughput - -A single NativeLink instance handles over a billion build requests -per month on modest hardware. That's `~400 req/s` sustained, -`p99 < 1ms` lookups. Hitting those numbers in a GC'd language -requires more horizontal scaling, more memory, more tuning. - -## What it costs - -- Compile times. Cargo builds are slower than `go build`. Mitigated - by sccache + NativeLink itself. -- Smaller talent pool. Hiring Rust engineers is harder than hiring Go - engineers. We've found this less painful than expected — the people - who write distributed-system Rust tend to be exactly the people you - want writing distributed systems. diff --git a/web/apps/docs/content/docs/faq/toolchains.mdx b/web/apps/docs/content/docs/faq/toolchains.mdx deleted file mode 100644 index 248c38aa9..000000000 --- a/web/apps/docs/content/docs/faq/toolchains.mdx +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: What are toolchains? -description: How NativeLink represents compilers, linkers, and the runtime they need. ---- - -A toolchain is the bundle of binaries and configuration NativeLink -needs to run a build action — the compiler, the linker, the standard -library headers, the `cc` wrapper script, any shared library the -compiler depends on. Everything that touches the action. - -For caching and hermeticity to work, the toolchain has to be **fully -declared as inputs**. If the build implicitly picks up `clang` from -`$PATH`, two machines with slightly different `clang` versions produce -different outputs but identical action hashes. The cache lies; you -debug for an afternoon. - -## Three ways to provide one - -| Provider | Hermetic? | Setup cost | -| ------------------------- | ------------ | -------------- | -| **Nix flake** | Fully | Highest | -| **Bazel rules_cc / rules_rust** | Mostly | Medium | -| **System (`$PATH`)** | No | Lowest | - -### Nix - -The recommended path for [LRE](/explanations/lre) and any -deployment where reproducibility matters. The toolchain is identified -by a hash of its inputs; two machines pulling the same flake get -byte-identical binaries. - -### Bazel rules_cc / rules_rust - -The Bazel-native option. Pin the toolchain version in your -`MODULE.bazel`, register it as a platform, point actions at it. -Reasonable for most Bazel monorepos. - -### System tooling - -Use whatever's installed. Quick to set up, no hermeticity guarantees. -Reasonable for "I just want to try the cache out for a day." - -## Tagging actions with a toolchain - -NativeLink matches actions to workers via `platform_properties`. A -worker that has the `nvidia-a100` GPU tagged will be the only worker -that receives actions requesting that GPU. Same applies to toolchain -versions, OS, CPU count, custom labels — anything the cluster -operator configures. - -For the configuration knobs see -[Configuration → Production](/configuration/production#scheduler-ha-with-sticky-workers). diff --git a/web/apps/docs/content/docs/getting-started/on-prem.mdx b/web/apps/docs/content/docs/getting-started/on-prem.mdx index fb47d20ae..c7834b1c1 100644 --- a/web/apps/docs/content/docs/getting-started/on-prem.mdx +++ b/web/apps/docs/content/docs/getting-started/on-prem.mdx @@ -13,18 +13,19 @@ serves your team without 3 AM pages. Pick on-prem when one of these is true: - **Data residency.** Build artifacts can carry source code, - toolchains, even credentials. If those have to stay in a specific - region (EU GDPR, US FedRAMP boundaries, air-gapped corp networks), - managed Cloud isn't an option yet. + toolchains, even credentials. Self-hosting keeps them in whatever + region or boundary you need (EU GDPR, US FedRAMP boundaries, + air-gapped corp networks). - **Specialised hardware.** GPU workers, ARM cross-compile fleets, - in-house silicon. Cloud supports the common cases; on-prem lets you - use anything that can run a Linux binary. + in-house silicon. On-prem lets you use anything that can run a + Linux binary. - **You already operate stateful services.** If your team owns Kubernetes, Postgres, S3-compatible storage, adding NativeLink is marginal work. -If none of those apply, NativeLink Cloud is cheaper, faster to -provision, and one fewer pager rotation. +If you'd rather not run it yourself, +[Enterprise](https://nativelink.com/pricing) offers a managed +deployment. ## What ships in the box @@ -66,7 +67,7 @@ each independently.
  • **Plan capacity.** Heuristics from production clusters: - - CAS storage: 5–20 GB per active developer per week, depending on + - CAS storage: 5–20 GB per active developer, depending on language. C++ skews high; Go skews low. - Worker CPU: 1 vCPU per concurrent action. Headroom matters more than peak. @@ -92,7 +93,7 @@ specific version your config references — `latest` works but pinning avoids surprises. ```bash -docker pull ghcr.io/tracemachina/nativelink:v1.4.0 +docker pull ghcr.io/tracemachina/nativelink:v1.6.1 ``` The [`/pkgs/container/nativelink`](https://github.com/TraceMachina/nativelink/pkgs/container/nativelink) @@ -113,6 +114,37 @@ clients. Snapshot strategy depends on the backend: The Action Cache can be wiped without data loss; you'll re-execute everything until it warms back up. +## FAQ + + + + Yes, for permitted use. Most of the monorepo is + `FSL-1.1-Apache-2.0` — internal use, modification, and redistribution + for non-competing purposes are allowed. Metrics and remote persistent + workers are Business Source License modules: fine for an individual + developer's cache, but shared, production, or commercial use of those + modules needs NativeLink Enterprise or an intentionally + inexpensive commercial license. Meaningful contributors may be + eligible for waivers — contact the maintainers before relying on one. + The practical summary is on the + [license page](https://nativelink.com/license). + + + Compute for the control plane (a few small VMs), CAS storage — the + dominant cost in a healthy cluster — worker compute, and the engineer + hours to run it all. For most teams under ~30 engineers, self-hosting + is cheaper; past that, a managed + [Enterprise](https://nativelink.com/pricing) deployment + usually wins on engineer time alone. + + + No. Nothing artificially limits cache size, action count, + worker count, or team size — the self-hosted build is the same + codebase run in production, subject to each module's license, minus + the operational tooling and support the paid tiers add. + + + ## What's next - [Configuration → Production](/configuration/production) — the diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/buck2.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/buck2.mdx index f734543ca..d70d95914 100644 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/buck2.mdx +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/buck2.mdx @@ -91,3 +91,19 @@ download paths are working. sets `remote_enabled = True`. - **Instance-name errors.** Make sure Buck2's `instance_name` matches the NativeLink config. The integration test uses `main`. + +## FAQ + + + + `engine_address`, `action_cache_address`, and `cas_address` are + separate settings because Buck2 lets you split those services across + hosts. NativeLink serves them all from one listener, so all three + point at the same `host:port`. + + + Both. Execution needs an execution platform registered with + `remote_enabled = True` (above) plus a NativeLink scheduler and + worker — the integration test config runs one of each. + + diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/buildstream.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/buildstream.mdx index da02be24c..556f39513 100644 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/buildstream.mdx +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/buildstream.mdx @@ -115,3 +115,19 @@ and checks that NativeLink did not log an error. - **Remote actions do not match a worker.** Compare the platform properties BuildStream requests with the properties your NativeLink worker advertises. The integration test worker advertises `ISA: x86-64`. + +## FAQ + + + + They configure different BuildStream subsystems — artifact push/pull + storage versus the execution, action-cache, and storage services used + for remote builds. Pointing every URL at the same NativeLink listener + is fine; it exposes all of those services on one port. + + + BuildStream expresses these endpoints as URLs rather than bare + `host:port` pairs. The checked-in integration test runs without TLS, + hence `http://localhost:50051`. + + diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/cmake-recc.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/cmake-recc.mdx index a0b8731c7..b2167a1f3 100644 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/cmake-recc.mdx +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/cmake-recc.mdx @@ -36,19 +36,16 @@ giving you cross-machine and cross-branch caching. ## 1. Start NativeLink ```sh -curl -O https://raw.githubusercontent.com/TraceMachina/nativelink/v1.0.0/nativelink-config/examples/basic_cas.json5 +curl -O https://raw.githubusercontent.com/TraceMachina/nativelink/v1.6.1/nativelink-config/examples/basic_cas.json5 docker run -d --name nativelink \ - --platform linux/amd64 \ -v $(pwd)/basic_cas.json5:/config \ -p 50051:50051 -p 50061:50061 \ - ghcr.io/tracemachina/nativelink:v1.0.0 config + ghcr.io/tracemachina/nativelink:v1.6.1 config ``` -The prebuilt image is x86_64. `--platform linux/amd64` is a no-op on Linux -x86_64 and triggers fast emulation on Apple Silicon. (Linux arm64 users: -build NativeLink with `nix run github:TraceMachina/nativelink ./basic_cas.json5` -instead.) +The image is multi-arch (x86_64 and ARM64) as of v1.6.0, so it runs +natively on Linux and Apple Silicon alike. Confirm it came up: @@ -195,6 +192,27 @@ actions, not link actions, by default. docker stop nativelink && docker rm nativelink ``` +## FAQ + + + + Not in this setup — `RECC_CACHE_ONLY=1` means misses compile locally + and only the outputs travel through NativeLink. Drop that variable + once you have remote workers configured and recc will dispatch + compiles to them. + + + recc ships compile actions only by default; links always run locally. + For remote link steps you want a full RBE client — see + [Classic RBE examples](/rbe/examples). + + + Point `RECC_SERVER` at a shared NativeLink deployment and keep + `RECC_INSTANCE` identical across machines — mismatched instance names + produce a silently empty cache. + + + ## Going further - Point `RECC_SERVER` at a shared NativeLink deployment (cloud or diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/index.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/index.mdx index 1364bf34b..dbd1652e0 100644 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/index.mdx +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/index.mdx @@ -1,6 +1,6 @@ --- title: Other build systems -description: Use NativeLink without Bazel — Buck2, Reclient, Pants, BuildStream, and CMake with recc. +description: Use NativeLink without Bazel — Buck2, Siso, Pants, BuildStream, and CMake with recc. --- NativeLink speaks the standard Remote Execution API. If your build tool @@ -12,8 +12,8 @@ your build files. - [Buck2](/getting-started/other-build-systems/buck2) — use Buck2's built-in remote execution client with NativeLink as CAS, Action Cache, and executor. -- [Reclient](/getting-started/other-build-systems/reclient) — configure - `reproxy` and `rewrapper` for Chromium-style builds. +- [Siso](/getting-started/other-build-systems/siso) — configure + Chromium's Ninja replacement to use NativeLink through the RE API. - [Pants](/getting-started/other-build-systems/pants) — enable remote cache reads and writes from `pants.toml`. - [BuildStream](/getting-started/other-build-systems/buildstream) — point @@ -35,3 +35,27 @@ For a local Docker server, start with [Getting Started → Setup](/getting-started/setup). For the Buck2 integration test shape, see [`integration_tests/buck2/buck2_cas.json5`](https://github.com/TraceMachina/nativelink/tree/main/integration_tests/buck2/buck2_cas.json5). + +## FAQ + + + + Yes — they speak the same protocol against the same endpoint. Each + tool hashes its actions differently, so tools won't share entries + with each other, but every client of the same tool and toolchain + will. + + + Action hashes computed under different `instance_name` values never + collide, and a mismatch produces no error — just a cache that looks + permanently empty. Every client targeting a cache must send the same + instance name the server exposes. + + + If you're on CMake, + [recc in cache-only mode](/getting-started/other-build-systems/cmake-recc) + needs no worker fleet and no build-file changes. For Bazel, two + `.bazelrc` lines against the [Setup](/getting-started/setup) server + do it. + + diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/meta.json b/web/apps/docs/content/docs/getting-started/other-build-systems/meta.json index 1e4ab9cf8..2f96cd11f 100644 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/meta.json +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/meta.json @@ -1,7 +1,7 @@ { "pages": [ "buck2", - "reclient", + "siso", "pants", "buildstream", "cmake-recc" diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/pants.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/pants.mdx index 033ae8e69..e1da90fb0 100644 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/pants.mdx +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/pants.mdx @@ -55,3 +55,19 @@ and toolchains aligned. config. The local examples use `main`. - **Connection failures.** Pants expects a `grpc://` URL in `remote_store_address`. + +## FAQ + + + + To let you split roles: CI can populate the cache + (`remote_cache_write = true`) while developer laptops only read from + it. For a single shared setup, enable both. + + + Yes — it's the same Remote Execution API — but the worker environment + must match what Pants sends. Get remote caching working first, then + align worker platform properties and toolchains before enabling + execution. + + diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/reclient.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/reclient.mdx deleted file mode 100644 index 17db1a152..000000000 --- a/web/apps/docs/content/docs/getting-started/other-build-systems/reclient.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: Reclient -description: Point Reclient at NativeLink for Chromium-style remote caching and execution. ---- - -Reclient speaks the Remote Execution API through a local daemon, -`reproxy`, and command wrapper, `rewrapper`. NativeLink can be the -backend for Reclient clients such as Chromium and other GN/Ninja builds. - -For a production Chromium walkthrough, see -[Deployment → Chromium](/deployment/chromium). - -## Local cache-only setup - -Start NativeLink on `localhost:50051` with instance name `main`, then -export the environment variables Reclient reads: - -```bash -export RBE_service=localhost:50051 -export RBE_instance=main -export RBE_service_no_security=true -``` - -For cache-only compiler wrapping, run `reproxy` and invoke a command with -`rewrapper`: - -```bash -reproxy & -rewrapper -- clang++ -c hello.cc -o hello.o -``` - -For CMake projects, [`recc`](/getting-started/other-build-systems/cmake-recc) -is often the smaller setup. It uses the same Remote Execution API but fits -CMake compiler-launcher workflows directly. - -## Chromium-style setup - -Chromium checks in Reclient configs. Point them at NativeLink by enabling -remote execution in GN: - -```bash -gn gen out/Default --args=' - use_remoteexec=true - use_goma=false - use_siso=false - reclient_cfg_dir="../../buildtools/reclient_cfgs/chromium-browser-clang" -' -``` - -Start the daemon before building: - -```bash -buildtools/reclient/bootstrap --re_proxy=buildtools/reclient/reproxy -autoninja -C out/Default chrome -``` - -## Production TLS settings - -For a secured NativeLink endpoint, set the Reclient TLS variables instead -of `RBE_service_no_security=true`: - -```bash -export RBE_service=cas.nativelink.internal:50051 -export RBE_instance=main -export RBE_service_no_security=false -export RBE_tls_client_auth_cert=/etc/nativelink/tls/client.crt -export RBE_tls_client_auth_key=/etc/nativelink/tls/client.key -export RBE_tls_ca_cert=/etc/nativelink/tls/ca.crt -``` - -## Confirm it is working - -Use Reclient stats after a build: - -```bash -reclient stats -``` - -On a warm cache, cache hits should climb and network errors should stay at -zero. If actions fall back to local execution, compare the platform -properties Reclient requests with the properties your NativeLink workers -advertise. diff --git a/web/apps/docs/content/docs/getting-started/other-build-systems/siso.mdx b/web/apps/docs/content/docs/getting-started/other-build-systems/siso.mdx new file mode 100644 index 000000000..93b08200e --- /dev/null +++ b/web/apps/docs/content/docs/getting-started/other-build-systems/siso.mdx @@ -0,0 +1,83 @@ +--- +title: Siso +description: Point Siso at NativeLink for Chromium-style remote caching and execution. +--- + +[Siso](https://chromium.googlesource.com/build/+/refs/heads/main/siso/README.md) +is Chromium's Ninja replacement. It runs build actions on RBE natively, +and NativeLink can be the RE API backend for Chromium and other +Siso-driven builds. + +For a production Chromium walkthrough, see +[Deployment → Chromium](/deployment/chromium). + +## Local endpoint setup + +Start NativeLink on `localhost:50051` with instance name `main`, then +export the environment variables Siso reads: + +```bash +export SISO_REAPI_ADDRESS=localhost:50051 +export SISO_REAPI_INSTANCE=main +export RBE_service_no_security=true +``` + +For CMake projects, [`recc`](/getting-started/other-build-systems/cmake-recc) +is often the smaller setup. It uses the same Remote Execution API but fits +CMake compiler-launcher workflows directly. + +## Chromium-style setup + +Chromium checks in Siso configs. Point them at NativeLink by enabling +remote execution in GN: + +```bash +gn gen out/Default --args=' + use_remoteexec=true + use_goma=false + use_siso=true +' +``` + +Build normally with `autoninja`; it detects `use_siso=true` and invokes +`siso ninja`: + +```bash +autoninja -C out/Default chrome +``` + +## Production TLS settings + +For a secured NativeLink endpoint, set the Siso TLS variables instead +of `RBE_service_no_security=true`: + +```bash +export SISO_REAPI_ADDRESS=cas.nativelink.internal:50051 +export SISO_REAPI_INSTANCE=main +export RBE_service_no_security=false +export RBE_tls_client_auth_cert=/etc/nativelink/tls/client.crt +export RBE_tls_client_auth_key=/etc/nativelink/tls/client.key +export RBE_tls_ca_cert=/etc/nativelink/tls/ca.crt +``` + +## Confirm it is working + +On a warm cache, cache hits should climb and network errors should stay at +zero. If actions fall back to local execution, compare the platform +properties Siso requests with the properties your NativeLink workers +advertise. + +## FAQ + + + + Only for TLS-free local development. Against any shared endpoint, use + the TLS variables shown above instead. + + + Siso replaces Ninja and speaks full remote execution — it's the path + for Chromium-style builds. recc is a compiler launcher for ordinary + CMake projects that want caching with minimal setup — see + [CMake with recc](/getting-started/other-build-systems/cmake-recc). + + diff --git a/web/apps/docs/content/docs/getting-started/setup.mdx b/web/apps/docs/content/docs/getting-started/setup.mdx index 4585ebd67..66c0f6b0f 100644 --- a/web/apps/docs/content/docs/getting-started/setup.mdx +++ b/web/apps/docs/content/docs/getting-started/setup.mdx @@ -9,7 +9,7 @@ system to the running cluster. You need a build tool that speaks the Remote Execution API — Bazel, - Buck2, Reclient, Pants, Goma, or CMake via recc. For the Docker path, + Buck2, Siso, Pants, Goma, or CMake via recc. For the Docker path, Docker 24+. For the Nix path, a recent Nix install with flakes enabled. @@ -18,22 +18,24 @@ system to the running cluster. The fastest way is the prebuilt container image. It runs anywhere Docker runs and ships with a tested configuration. - + - + ```bash # Grab a known-good basic configuration -curl -O https://raw.githubusercontent.com/TraceMachina/nativelink/v1.4.0/nativelink-config/examples/basic_cas.json5 +curl -O https://raw.githubusercontent.com/TraceMachina/nativelink/v1.6.1/nativelink-config/examples/basic_cas.json5 # Run the official image docker run \ -v $(pwd)/basic_cas.json5:/config \ -p 50051:50051 \ - ghcr.io/tracemachina/nativelink:v1.4.0 config + ghcr.io/tracemachina/nativelink:v1.6.1 config ``` -The server is now listening on `localhost:50051`. +The image is multi-arch — x86_64 and ARM64 both run natively (use +v1.6.0 or later; earlier tags are x86_64-only). The server is now +listening on `localhost:50051`. @@ -46,11 +48,14 @@ nix run github:TraceMachina/nativelink ./basic_cas.json5 ``` Slower than the prebuilt image because it builds from source, but works on -macOS (Apple Silicon and Intel) and any Linux with Nix. Also the only path -that supports Apple Silicon natively at the moment. +macOS (Apple Silicon and Intel) and any Linux with Nix. Use it when you +want a native binary instead of a container — the Docker path above also +runs natively on Apple Silicon. - Executables built for macOS link dynamically against libraries from the + - **Prerequisites**: Make sure your Nix installation has experimental features enabled (add `experimental-features = nix-command flakes` to your `~/.config/nix/nix.conf`). + - **Disk Space**: The installation and build process requires downloading and compiling toolchains and compilers. Ensure you have at least **15–20 GB of free space** on your drive. + - **Portability**: Executables built for macOS link dynamically against libraries from the Nix store. They will not run on systems without those libraries available. Stick to the Docker path if you need to copy the binary to another machine. @@ -58,21 +63,21 @@ that supports Apple Silicon natively at the moment. - + ```powershell Invoke-WebRequest ` - -Uri "https://raw.githubusercontent.com/TraceMachina/nativelink/v1.4.0/nativelink-config/examples/basic_cas.json5" ` + -Uri "https://raw.githubusercontent.com/TraceMachina/nativelink/v1.6.1/nativelink-config/examples/basic_cas.json5" ` -OutFile "basic_cas.json5" docker run ` -v ${PWD}/basic_cas.json5:/config ` -p 50051:50051 ` - ghcr.io/tracemachina/nativelink:v1.4.0 config + ghcr.io/tracemachina/nativelink:v1.6.1 config ``` -Native Windows support is x86_64 only. ARM64 Windows users should use -WSL2 with the Linux instructions above. +The multi-arch image covers x86_64 and ARM64 Windows machines alike. +WSL2 with the Linux instructions above works too. @@ -91,7 +96,7 @@ the connection succeeding does. ## Point your build system at it - + @@ -136,20 +141,17 @@ buck2 build //... --remote-cache - + -Set the environment variables Reclient reads: +Set the endpoint variables Siso reads: ```bash -export RBE_service=localhost:50051 -export RBE_instance=main +export SISO_REAPI_ADDRESS=localhost:50051 +export SISO_REAPI_INSTANCE=main export RBE_service_no_security=true # only for local TLS-free dev - -reproxy & -rewrapper -- ``` -The Chromium build is the canonical Reclient consumer; see +The Chromium build is the canonical Siso consumer; see [Deployment → Chromium](/deployment/chromium) for a full example. @@ -212,6 +214,31 @@ section below. `-v $(pwd)/basic_cas.json5:/config:Z`. +## FAQ + + + + Every action's inputs — source digests, the compiler binary, the + exact command line, declared headers — are hashed together, and the + action's outputs are stored under that hash. Anyone whose action + hashes identically gets the stored outputs back in milliseconds + instead of redoing the work. + + + The hash covers every declared input, so any difference — a header, + a compiler patch version, a leaked environment variable — produces a + new hash. That's by design: a hit is a guarantee the result is + identical. If you see misses where you expect hits, start with the + [troubleshooting](#troubleshooting) section above and the + [hermeticity FAQ](/explanations/lre#faq). + + + Yes — set both, even to the same address. Without `--remote_cache`, + Bazel calls `Execute` with an action digest it never uploaded, and + the server rejects it with `Action ... is missing from CAS`. + + + ## What's next You have a local cache running. The natural next steps: diff --git a/web/apps/docs/content/docs/index.mdx b/web/apps/docs/content/docs/index.mdx index 390dec76d..5d64ef772 100644 --- a/web/apps/docs/content/docs/index.mdx +++ b/web/apps/docs/content/docs/index.mdx @@ -4,7 +4,7 @@ description: NativeLink is a high-performance remote build cache and execution p --- NativeLink is a high-performance remote build cache and execution platform for -build systems that speak the Remote Execution API — **Bazel, Buck2, Reclient, +build systems that speak the Remote Execution API — **Bazel, Buck2, Siso, Pants, Goma**, and **CMake via recc**. It's open source, written in Rust, and battle-tested on over a billion build requests a month. @@ -15,7 +15,7 @@ section landings are accurate, page bodies are coming. If you're integrating NativeLink with an AI coding agent (Claude Code, Cursor, Copilot Workspace, Devin), start with [Getting Started → Setup](/getting-started/setup) - and then read [Why hermeticity matters](/faq/hermeticity). + and then read [why hermeticity matters](/explanations/lre#faq). ## Pick a starting point @@ -31,7 +31,7 @@ serves its job well. - [NativeLink on-prem](/getting-started/on-prem) — a single-server deployment that survives a team-wide rollout. - [Other build systems](/getting-started/other-build-systems) — using NativeLink - without Bazel (Buck2, Reclient, Pants, CMake). + without Bazel (Buck2, Siso, Pants, CMake). ### I want to configure or operate it @@ -53,10 +53,6 @@ serves its job well. - [History](/explanations/history) — why NativeLink exists and what came before. -### I have a specific question - -- [FAQ](/faq/cost) — short answers to the questions we get most. - ### I want to contribute - [Contribution guidelines](/contribute/guidelines) — what we accept, @@ -70,3 +66,33 @@ serves its job well. configurable knob, autogenerated from the source. - [Glossary](/reference/glossary) - [Changelog](/reference/changelog) + +## FAQ + +Every page on this site ends with an FAQ covering the questions we +get most about that topic. The ones we get most overall: + + + + Yes — NativeLink is source-available and free for permitted + self-hosted use. Most of the monorepo is licensed under + `FSL-1.1-Apache-2.0`; a few modules (metrics, remote persistent + workers) are under the Business Source License, and a paid + [Enterprise](https://nativelink.com/pricing) tier exists if + you'd rather not run it yourself. The licensing details are in + [NativeLink on-prem](/getting-started/on-prem#faq). + + + Any client that speaks the Remote Execution API: Bazel, Buck2, Siso, + Pants, BuildStream, Goma, and plain CMake via + [recc](/getting-started/other-build-systems/cmake-recc) — with no + build-file rewrites. See + [Other build systems](/getting-started/other-build-systems). + + + Linux and Windows on x86_64 and ARM64 via the multi-arch Docker image + (`ghcr.io/tracemachina/nativelink`, v1.6.0+), and macOS (Apple + Silicon and Intel) via the Docker image or a from-source Nix build. + See [Setup](/getting-started/setup). + + diff --git a/web/apps/docs/content/docs/meta.json b/web/apps/docs/content/docs/meta.json index 3b845589d..846405094 100644 --- a/web/apps/docs/content/docs/meta.json +++ b/web/apps/docs/content/docs/meta.json @@ -8,7 +8,6 @@ "deployment", "---Learn---", "explanations", - "faq", "---Develop---", "contribute", "reference" diff --git a/web/apps/docs/content/docs/rbe/examples.mdx b/web/apps/docs/content/docs/rbe/examples.mdx index 31666a1ea..f4403d273 100644 --- a/web/apps/docs/content/docs/rbe/examples.mdx +++ b/web/apps/docs/content/docs/rbe/examples.mdx @@ -113,6 +113,30 @@ Start with cache-only. Move to full RE when the team feels the local build CPU bottleneck. Move to hybrid only when you have telemetry showing where time goes. +## FAQ + + + + The action: input digests, the command line, and the platform + requirements. The worker fetches inputs from the CAS by hash, runs + the command, and uploads outputs the same way — nothing else crosses + the wire. + + + Throughput (a fleet has more cores than any laptop), hermeticity (one + job, one environment, no stale state), and cost — build hardware goes + from the 5-10% utilization of idle CI runners to 60-80% on a shared + fleet. + + + Three levels of rigor: a Nix flake (fully hermetic — the + [LRE](/explanations/lre) path), Bazel's `rules_cc` / `rules_rust` + pinned in `MODULE.bazel` (mostly hermetic), or whatever's on `$PATH` + (quick, no guarantees). Either way, the scheduler routes actions to + matching workers via `platform_properties`. + + + ## What's next - [Nix templates](/rbe/nix-templates) — runnable testbeds for diff --git a/web/apps/docs/content/docs/rbe/local-remote-execution.mdx b/web/apps/docs/content/docs/rbe/local-remote-execution.mdx new file mode 100644 index 000000000..49bd9e431 --- /dev/null +++ b/web/apps/docs/content/docs/rbe/local-remote-execution.mdx @@ -0,0 +1,207 @@ +--- +title: Local Remote Execution +description: The Nix-pinned toolchain workflow behind LRE, walked through and tested end to end — including exactly what runs fully local and what still needs a real worker. +--- + +[Explanations → LRE](/explanations/lre) covers what Local Remote +Execution is and why it exists. This page is the hands-on version: +the exact commands, run for real, plus two gotchas the flake alone +doesn't mention. + + + `@local-remote-execution` ships **two** toolchain families, and they + behave differently once you leave `x86_64-linux`: + + - **Rust** (`@local-remote-execution//rust/...`) has a real, natively + built toolchain for `aarch64-darwin`, `aarch64-linux`, + `x86_64-darwin`, and `x86_64-linux`. Actions using it run fully + local — no network, no container. + - **C++** (`@local-remote-execution//generated-cc/...`) — what the + `bazel` template's own example uses — is a single Linux container + config (`ghcr.io/tracemachina/nativelink-worker-lre-cc:...`). + On any host, actions using it dispatch to a real worker running + that container. On macOS this means a network round-trip even + though the toolchain is Nix-pinned — LRE gives you hermeticity + here, not offline-ness. + + Below is what actually happened running the C++ example on + aarch64-darwin. If your project is Rust, swap the target and you get + the fully-local experience the intro promises. + + +## 1. Install Nix + +Flakes enabled. The +[next-gen installer](https://github.com/NixOS/experimental-nix-installer) +is the easiest path. + +## 2. Pull the template + +```bash +mkdir my-lre-test && cd my-lre-test +nix flake init -t github:TraceMachina/nativelink#bazel +``` + +This writes a `flake.nix` that imports `nativelink.flakeModules.lre` +and pins `lre = { inherit (pkgs.lre.lre-cc.meta) Env; };`, plus the +`hello-world.cpp` example, its `BUILD.bazel`, and `platforms/BUILD.bazel`. + +## 3. Init git — this step is not optional + +```bash +git init && git add -A +``` + + + The flake module's install script checks for a `.git` directory + before generating anything. Running `nix develop` in a plain + (non-git) folder prints this and moves on without writing + `lre.bazelrc` — no error, no toolchain: + + ```text + WARNING: lre: .git not found; skipping installation. + ``` + + +## 4. Enter the dev shell + +```bash +nix develop +``` + +This fetches the Nix-pinned Clang and writes `lre.bazelrc`. On +aarch64-darwin, the generated file looked like this (paths and hashes +will differ on your machine): + +```bash +# These flags are dynamically generated by the lre flake module. +# +# PATH=/nix/store/.../llvm-binutils-wrapper-20.1.1/bin:/nix/store/.../customClang/bin:... +# CC=/nix/store/.../customClang/bin/customClang + +# Bazel-side configuration for LRE. +build --define=EXECUTOR=remote +build --extra_execution_platforms=@local-remote-execution//rust/platforms:aarch64-apple-darwin +build --extra_toolchains=@local-remote-execution//rust:rust-aarch64-darwin +build --extra_toolchains=@local-remote-execution//rust:rustfmt-aarch64-darwin +build --platforms=@local-remote-execution//rust/platforms:aarch64-apple-darwin +``` + +Notice this registers the **Rust** platform even though the flake +requested the `lre-cc` `Env` — there's no local aarch64-darwin config +under `generated-cc`, so the module falls back to the toolchain that +does have one. The template's `.bazelrc` separately adds +`--extra_execution_platforms=@//platforms:lre-cc` for the C++ example, +which is the container-based platform from the callout above. + +## 5. Point `user.bazelrc` at a real cache and executor + +The template's own generator writes `user.bazelrc` with the literal +word `TODO` as every value — this isn't a placeholder left in this +page, it's what `nix flake init` puts on disk for you to edit: + +```bash +build --remote_cache=grpcs://TODO +build --bes_backend=grpcs://TODO +build --remote_timeout=600 +build --remote_executor=grpcs://TODO +``` + +Replace all three `TODO`s with your own cluster's endpoint. +Concretely, filled in for a plain local +cluster (no TLS, so `grpc://` instead of `grpcs://`, and no BES +endpoint to point at) — this is the exact `user.bazelrc` used to +produce the verified output in step 4 above: + +```bash +build --remote_cache=grpc://127.0.0.1:50051 +build --remote_timeout=600 +build --remote_executor=grpc://127.0.0.1:50051 +``` + +A TLS-terminated self-hosted +cluster looks the same shape, just with `grpcs://` and your cluster's +real hostnames in place of `127.0.0.1:50051`, plus a `bes_backend` +line if you want build results streamed there. + +If you build before editing `user.bazelrc` at all, Bazel fails fast on +the literal hostname `TODO` — here's the exact error that produces, +captured from a real run, so you recognize it as "I forgot to edit +`user.bazelrc`" rather than something else being wrong: + +```text +[8 / 10] Compiling src/hello-world.cpp; 0s remote, remote-cache +ERROR: BUILD.bazel:3:10: Compiling src/hello-world.cpp failed: + Failed to query remote execution capabilities: UNAVAILABLE: Unable to resolve host TODO +``` + +Everything before that DNS failure worked correctly — the Nix +toolchain, the Bazel platform wiring, and the `lre-cc` execution +platform selection (`0s remote, remote-cache` means Bazel committed to +executing it remotely). Once real values replace `TODO`, this step +just works. + +## 6. Build + +```bash +bazel build hello-world +``` + +With a real endpoint in `user.bazelrc` and a worker running the +`nativelink-worker-lre-cc` image available to it, this compiles +`src/hello-world.cpp` on that worker and returns the binary through +the same CAS your local Bazel reads from. Re-run and it's a cache hit. + + + You don't need a full cluster to see the cache side of this working. + [Local cache and executor](/rbe/local-testing) starts a plain + NativeLink instance on `localhost` — enough to validate + `remote_cache` against real credentials before you also need a + worker that matches `lre-cc`'s platform requirements. + + +## Troubleshooting + + + If cache hits between local and remote execution stop happening, + compare `lre.bazelrc`'s paths against the toolchain configs in the + `@local-remote-execution` module at the commit pinned in your + `MODULE.bazel` / `flake.nix`. A version drift between the two is the + most common cause. + + + + The template above bootstraps a new project. For the flake-parts + module wiring, `bazel_dep` override, and `try-import` setup to add + the same toolchains to a project you already have, see + [`local-remote-execution/README.md`](https://github.com/TraceMachina/nativelink/blob/main/local-remote-execution/README.md) + — it also covers verifying the setup against a Kubernetes cluster. + + +## FAQ + + + + [Local cache and executor](/rbe/local-testing) validates the protocol + with whatever toolchain is on your `PATH` — it has no toolchain + opinion. This page pins the toolchain with Nix so local and remote + actions hash identically. Run that one first if you just want to see + `Execute` work. + + + No — the guarantee *is* the Nix pinning: every tool lives at a + content-addressed `/nix/store` path, which is what makes action + hashes match across machines. The server side, by contrast, runs fine + without Nix. + + + +## What's next + +- [Explanations → LRE](/explanations/lre) — the conceptual write-up. +- [Local cache and executor](/rbe/local-testing) — validate the + protocol side without Nix or a container-capable worker. +- [Nix templates](/rbe/nix-templates) — what else ships in the + `bazel` flake template. +- [Deployment → Kubernetes](/deployment/kubernetes) — running a real + worker fleet, including `lre-cc` workers, in production. diff --git a/web/apps/docs/content/docs/rbe/local-testing.mdx b/web/apps/docs/content/docs/rbe/local-testing.mdx new file mode 100644 index 000000000..69d96d656 --- /dev/null +++ b/web/apps/docs/content/docs/rbe/local-testing.mdx @@ -0,0 +1,220 @@ +--- +title: Local cache and executor +description: Run a full NativeLink cache and executor on your own machine and prove Bazel's remote caching and remote execution work — no Nix, no shared cluster. +--- + +Before pointing a build at a shared cluster — or before setting up +[Local Remote Execution](/rbe/local-remote-execution) — prove the +client side works against something you fully control: a NativeLink +cache and executor running on your own machine, using whatever +toolchain is already on your `PATH`. Nothing here talks to any +external or shared service, and nothing here requires Nix. + + + [Local Remote Execution](/rbe/local-remote-execution) is a specific + NativeLink feature: Nix-pinned toolchains that make local and remote + actions hash-identical. This page is narrower and has no toolchain + opinion at all — it's the fastest way to confirm a Bazel client can + talk to a real NativeLink `Execute` and CAS implementation before + you add Nix into the mix. + + +## What you get + +One `nativelink` process, one port for the client, a private port for +the worker: + + +{`flowchart LR + subgraph client[Your machine] + B[Bazel] + subgraph nl["nativelink process"] + direction LR + L["0.0.0.0:50051\\ncas · ac · bytestream\\nexecution · capabilities"] + W["0.0.0.0:50061\\nworker_api (private)"] + WK[local worker] + end + end + B -->|remote_cache\\n+ remote_executor| L + L --- W + W --- WK`} + + +Bazel's `--remote_cache` and `--remote_executor` both point at +`127.0.0.1:50051`. `50061` only exists so the worker can register with +the scheduler — Bazel never talks to it. + +## 1. Build `nativelink` + +```bash +bazel build //:nativelink +# or: cargo build --bin nativelink +``` + +## 2. Grab the config + +[`nativelink-config/examples/local_rbe_self_test.json5`](https://github.com/TraceMachina/nativelink/blob/main/nativelink-config/examples/local_rbe_self_test.json5) +is a complete, tested cluster — CAS, AC, a `simple` scheduler, and one +`local` worker, entirely on `localhost`: + +```json5 +{ + stores: [ + { name: "CAS_MAIN_STORE", filesystem: { /* ... */ } }, + { name: "AC_MAIN_STORE", filesystem: { /* ... */ } }, + { + // The worker's fast tier and the client-facing CAS share one store, + // so anything the worker produces is immediately visible to Bazel. + name: "WORKER_FAST_SLOW_STORE", + fast_slow: { + fast: { filesystem: { /* ... */ } }, + slow: { ref_store: { name: "CAS_MAIN_STORE" } }, + }, + }, + ], + schedulers: [{ + name: "MAIN_SCHEDULER", + simple: { supported_platform_properties: { cpu_count: "minimum" /* ... */ } }, + }], + workers: [{ + local: { + worker_api_endpoint: { uri: "grpc://127.0.0.1:50061" }, + cas_fast_slow_store: "WORKER_FAST_SLOW_STORE", + upload_action_result: { ac_store: "AC_MAIN_STORE" }, + platform_properties: { cpu_count: { values: ["1"] } /* ... */ }, + }, + }], + servers: [ + { + // Cache AND execution on one client-facing port. + name: "local", + listener: { http: { socket_address: "0.0.0.0:50051" } }, + services: { + cas: [{ cas_store: "CAS_MAIN_STORE" }], + ac: [{ ac_store: "AC_MAIN_STORE" }], + bytestream: [{ cas_store: "CAS_MAIN_STORE" }], + execution: [{ cas_store: "CAS_MAIN_STORE", scheduler: "MAIN_SCHEDULER" }], + capabilities: [{ remote_execution: { scheduler: "MAIN_SCHEDULER" } }], + }, + }, + { + // Private — only the worker connects here. + name: "worker_api", + listener: { http: { socket_address: "0.0.0.0:50061" } }, + services: { worker_api: { scheduler: "MAIN_SCHEDULER" }, health: {} }, + }, + ], +} +``` + + + Every service above omits `instance_name`, so it defaults to `""` — + the same default Bazel uses when you don't pass + `--remote_instance_name`. If you add an `instance_name` on the server + side, pass the matching `--remote_instance_name` flag, or every + request will fail with `'instance_name' not configured for ''`. + + +## 3. Start it + +```bash +nativelink ./nativelink-config/examples/local_rbe_self_test.json5 +``` + +```text +INFO nativelink: Ready, listening on 0.0.0.0:50051 +INFO nativelink: Ready, listening on 0.0.0.0:50061 +INFO nativelink_worker::local_worker: Worker registered with scheduler, worker_id: 1f175824-... +``` + +## 4. Point Bazel at it + +```bash +bazel test \ + --remote_cache=grpc://127.0.0.1:50051 \ + --remote_executor=grpc://127.0.0.1:50051 \ + --remote_default_exec_properties=cpu_count=1 \ + //your:target +``` + + + It's tempting to assume `--remote_executor` alone is enough — the + executor has to read/write CAS anyway. It isn't: without an explicit + `--remote_cache`, Bazel calls `Execute` with an action digest it + never uploaded, and the server correctly rejects it — + `FAILED_PRECONDITION: Action ... is missing from CAS`. Set both + flags. Pointing both at the same local address is exactly the point: + one machine, one cache, no separate remote service. + + +This repo tests itself exactly this way — see `build:self_test` and +`build:self_execute` in +[`.bazelrc`](https://github.com/TraceMachina/nativelink/blob/main/.bazelrc), +combined as `bazel test --config=self_test --config=self_execute`. +Copy that pattern into your own `.bazelrc` once the raw flags work. + +## 5. Verify + +First run — nothing cached yet, both actions run remote: + +```text +[4 / 5] 1 / 1 tests; Testing //:dummy_test; 0s remote, remote-cache +INFO: 5 processes: 3 internal, 3 remote. +//:dummy_test PASSED in 0.4s +``` + +`bazel clean`, run again — the genrule is a cache hit; the test +re-executes remotely because `--nocache_test_results` was set: + +```text +[7 / 8] Testing //:dummy_test; 0s remote +INFO: 8 processes: 2 remote cache hit, 6 internal, 1 remote. +//:dummy_test PASSED in 0.5s +``` + +Both runs were captured against the exact config above, on macOS +(arm64) — no Linux, no containers, no Nix. + +## Troubleshooting + + + The scheduler's `supported_platform_properties` must be satisfiable + by at least one worker's `platform_properties`, or matching actions + sit in the queue indefinitely with no error. Start with just + `cpu_count: "minimum"` on the scheduler and `cpu_count: { values: ["1"] }` + (or higher) on the worker — that alone unblocks most local setups. + + + + The worker's `use_namespaces` / `use_mount_namespace` options + sandbox actions with Linux namespaces and default to `false`. Leave + them unset on macOS — setting either to `true` on an unsupported + platform makes the worker exit immediately. + + +## FAQ + + + + Yes — the config exposes standard RE-API services, so Buck2, Pants, + Siso, or recc can point at `127.0.0.1:50051` the same way. The Bazel + flags are just the worked example. + + + The process counts in Bazel's output (`3 remote`, + `2 remote cache hit`) are the quick check; + `--execution_log_json_file` records the runner per action when you + need the per-action truth. + + + +## What's next + +- [Local Remote Execution](/rbe/local-remote-execution) — add + Nix-pinned, hermetic toolchains on top of this same idea. +- [Classic RBE examples](/rbe/examples) — the same three patterns + (cache-only, full RE, hybrid) once you're pointed at a shared cluster. +- [Nix templates](/rbe/nix-templates) — the `bazel` flake template, + for wiring a whole new project instead of the existing NativeLink repo. +- [Configuration → Introduction](/configuration/intro) — what every + field in the config above actually does. diff --git a/web/apps/docs/content/docs/rbe/meta.json b/web/apps/docs/content/docs/rbe/meta.json index 7b27cf714..0a9b612e5 100644 --- a/web/apps/docs/content/docs/rbe/meta.json +++ b/web/apps/docs/content/docs/rbe/meta.json @@ -1,5 +1,7 @@ { "pages": [ + "local-testing", + "local-remote-execution", "examples", "nix-templates" ], diff --git a/web/apps/docs/content/docs/rbe/nix-templates.mdx b/web/apps/docs/content/docs/rbe/nix-templates.mdx index 6235bd9f0..4d23818c4 100644 --- a/web/apps/docs/content/docs/rbe/nix-templates.mdx +++ b/web/apps/docs/content/docs/rbe/nix-templates.mdx @@ -1,12 +1,12 @@ --- title: Nix templates -description: Reproducible NativeLink testbeds in a single flake init command. +description: The Nix flake template NativeLink ships — Local Remote Execution with Bazel in one flake init command. --- -NativeLink ships Nix flake templates that spin up a complete -remote-execution environment in one command. Useful for -experimenting with configuration changes, demoing the system, or -debugging a regression on a known-good baseline. +NativeLink ships a Nix flake template that wires a Bazel project to +Local Remote Execution in one command. Useful for experimenting with +LRE, demoing the system, or debugging a regression on a known-good +baseline. ## Prerequisites @@ -21,102 +21,116 @@ debugging a regression on a known-good baseline. nix flake show github:TraceMachina/nativelink ``` -The templates we ship and maintain: + + Templates get added and removed between releases. Run the command + above rather than trusting a hardcoded list — including the one + below, which only reflects what's shipping as of this page's last + update. + -| Template | What it gives you | -| ------------- | ---------------------------------------------------------- | -| `bazel` | Bazel monorepo wired to a local NativeLink cluster. | -| `cargo` | Pure Cargo project with sccache pointing at NativeLink. | -| `lre` | Local Remote Execution — hermetic builds, no network. | -| `kubernetes` | `kind` cluster running the NativeLink Helm chart. | +| Template | What it gives you | +| --- | --- | +| `bazel` | A Bazel `cc_binary` project pre-wired for [Local Remote Execution](/explanations/lre): Nix-pinned toolchain, LRE Bazel module, and a `user.bazelrc` you point at a cache and executor. | ## The Bazel template -The fastest path to a working RBE setup: - ```bash mkdir my-rbe-test && cd my-rbe-test nix flake init -t github:TraceMachina/nativelink#bazel nix develop ``` -Inside the dev shell you have: - -- A pinned Bazel + Bazelisk. -- A NativeLink server binary. -- A `.bazelrc.local` already pointed at `localhost:50051`. - -Start the NativeLink server in one terminal: - -```bash -nativelink ./config/nativelink.json5 -``` - -Build the included sample target in another: +`nix develop` downloads the Nix-pinned toolchain and generates +`lre.bazelrc`, which the template's `.bazelrc` already `try-import`s. +It does **not** bundle a NativeLink server — you point it at one you +already have: ```bash -bazel build //hello +# In user.bazelrc +build --remote_cache=grpcs://TODO +build --bes_backend=grpcs://TODO +build --remote_timeout=600 +build --remote_executor=grpcs://TODO ``` -Re-run; everything should hit the cache. - -## The LRE template +Two ways to fill in `TODO` — [Local Remote Execution → Point +`user.bazelrc` at a real cache and executor](/rbe/local-remote-execution) +has a worked, filled-in example of the file below, whichever option +you pick: -For [Local Remote Execution](/explanations/lre): - -```bash -mkdir my-lre-test && cd my-lre-test -nix flake init -t github:TraceMachina/nativelink#lre -nix develop -``` +- **A self-hosted cluster** — your own endpoint, `grpcs://` if it + terminates TLS. +- **Nothing but your own machine** — drop the `s`, point both + `remote_cache` and `remote_executor` at `grpc://127.0.0.1:50051`. + [Local cache and executor](/rbe/local-testing) gets you a + from-scratch, credential-free instance in one command — enough to + validate `remote_cache`, though the included C++ example's `lre-cc` + platform still needs a worker running the matching container image + to actually execute (see [Local Remote Execution](/rbe/local-remote-execution) + for what that involves). -The dev shell provides a fully-hermetic Nix-pinned toolchain. -NativeLink runs on `localhost`; Bazel is pre-configured to use it. +Then build the included example: ```bash -nativelink ./config/lre.json5 -bazel build //hello +bazel build hello-world ``` -The first build of any target is the cost of compilation. Every -subsequent build is the cost of one network round-trip to -`localhost`. - -## The Kubernetes template - -For prototyping a real deployment without leaving your laptop: - -```bash -mkdir my-k8s-test && cd my-k8s-test -nix flake init -t github:TraceMachina/nativelink#kubernetes -nix develop -``` +Re-run; the cached actions should skip straight to a cache hit. -The flake includes `kind`, `kubectl`, `helm`, and the NativeLink -chart. Bring up a local cluster: +## Not shipped as flake templates today -```bash -kind create cluster -helm install nativelink ./chart -kubectl wait --for=condition=Ready pods --all -``` +Earlier drafts of this page also described `cargo`, `lre`, and +`kubernetes` templates. None exist in `flake.nix` right now — running +`nix flake init -t github:TraceMachina/nativelink#lre` (or `#cargo`, +`#kubernetes`) fails with `does not provide attribute 'templates.X'`. +If you followed a link here looking for one of those: -You now have CAS + scheduler + workers running in a local cluster -on your laptop. Port-forward `:50051` and point Bazel at it. +- **A local Bazel cluster with no Nix at all** — [Local cache and + executor](/rbe/local-testing) starts CAS, AC, a scheduler, and a + worker in one `nativelink` process. +- **A real Kubernetes deployment** — [Deployment → Kubernetes](/deployment/kubernetes) + covers the Helm chart directly; `kind` + that chart gets you the + same result a `kubernetes` template would have. +- **Cargo / sccache** — not currently packaged as a template; the + [`bazel` template](#the-bazel-template) above is the maintained path. ## Customising -Every template is a flake — fork and edit. The most common +The template is a flake — fork and edit. The most common modifications: -- Swap the `nativelink.json5` for a config matching your real - environment. -- Add custom worker platform properties. -- Pin to a specific NativeLink release (`inputs.nativelink.url`). +- Point `user.bazelrc` at your real cluster instead of a throwaway one. +- Add custom worker platform properties in `platforms/BUILD.bazel`. +- Pin to a specific NativeLink commit (`inputs.nativelink.url` in + `flake.nix`, kept in sync with the `local-remote-execution` module + override in `MODULE.bazel`). + +## FAQ + + + + A package manager that builds everything in isolation and addresses + results by a hash of all inputs — your `clang` lives at + `/nix/store/-clang-.../bin/clang`. That hash-pinned path is + exactly what LRE needs to make action hashes identical across + machines. + + + A learning curve (an unfamiliar language, terse error messages) and + the first `nix develop`, which downloads the full toolchain — about + 5 GB for this template. After that, entering the shell is instant. + + ## What's next -- [Architecture](/explanations/architecture) — the data flow - these templates exercise. -- [Configuration → Basic](/configuration/basic) — the JSON5 - the templates ship. +- [Local Remote Execution](/rbe/local-remote-execution) — this same + template, walked through step by step and tested for real. +- [Local cache and executor](/rbe/local-testing) — the fastest way to + get something running on `127.0.0.1` to point this template at. +- [Explanations → LRE](/explanations/lre) — what the toolchain pinning + this template sets up actually buys you. +- [Architecture](/explanations/architecture) — the data flow this + template exercises. +- [Configuration → Basic](/configuration/basic) — the JSON5 shape a + server you point this at should speak. diff --git a/web/apps/docs/content/docs/reference/changelog.mdx b/web/apps/docs/content/docs/reference/changelog.mdx deleted file mode 100644 index 18a832d51..000000000 --- a/web/apps/docs/content/docs/reference/changelog.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Changelog -description: Notable changes per release. Latest first. ---- - -The complete commit-level changelog lives in -[`CHANGELOG.md`](https://github.com/TraceMachina/nativelink/blob/main/CHANGELOG.md) -on the repository. This page summarises what's worth knowing per -release. - -## v1.3 — May 2026 - -- **Persistent workers.** Long-lived worker processes for hot - toolchains (JVM, Bazel-style). 5-20× speedup on JVM-heavy builds. - See [Persistent workers](/deployment/persistent-workers). -- **3× faster scheduler dispatch.** Lock-free path on the hot - routing function; `p99` dispatch latency drops below 1 ms. -- **First-class GPU support.** Workers can advertise CUDA / ROCm - capabilities; the scheduler matches actions on them. -- **`fast_slow` store layering** is now stable. - -## v1.2 — March 2026 - -- **LRE shipped to GA.** Hermetic builds on `localhost`, no Docker. -- **Multi-region CAS replication.** Built-in cross-region sync for - the durable store layer. -- **OpenTelemetry tracing** wired through every RPC. Configurable - sample rate per operation. - -## v1.1 — January 2026 - -- **Worker autoscaling improvements.** New `queue_depth` Prometheus - metric, drives HPA more accurately than CPU. -- **S3 store retry hardening.** Exponential backoff with jitter, - per-request circuit breakers. -- **Configurable Action Cache TTL.** Per-instance overrides. - -## v1.0 — November 2025 - -- **GA release.** Production-stable APIs, semver from this point on. -- **FSL-Apache licensing.** The repository moved to - `FSL-1.1-Apache-2.0` for most modules, with feature-specific - Business Source License modules called out in source headers. See - the [license page](https://nativelink.com/license). -- **Helm chart** for Kubernetes deployment promoted to stable. - -## v0.x — pre-GA - -The 0.x line was iterated heavily; see the -[GitHub release notes](https://github.com/TraceMachina/nativelink/releases) -for the full history. diff --git a/web/apps/docs/content/docs/reference/glossary.mdx b/web/apps/docs/content/docs/reference/glossary.mdx index aba4d81e7..2278f07c7 100644 --- a/web/apps/docs/content/docs/reference/glossary.mdx +++ b/web/apps/docs/content/docs/reference/glossary.mdx @@ -34,7 +34,7 @@ A content hash plus a size. Used everywhere instead of file paths. A build whose outputs depend only on its declared inputs. Same inputs → same outputs, on any machine, any time. See -[How do I make my Bazel setup hermetic?](/faq/hermeticity). +[the hermeticity FAQ](/explanations/lre#faq). ## Instance name @@ -67,15 +67,19 @@ in-flight actions. ## Worker The process that runs an action. Fetches inputs from CAS, runs the -command in a sandbox, uploads outputs to CAS. +command, uploads outputs to CAS. -## Sandbox +## Isolation -The isolated environment a worker runs an action in. On Linux, -typically `bwrap` or `landlock`; on macOS, `sandbox-exec`. The -sandbox makes hermeticity enforceable. +Keeping an action from seeing state outside its declared inputs. +On Linux, workers can isolate actions with kernel namespaces via +the `use_namespaces` and `use_mount_namespace` worker options, +which also reap zombie processes and improve hermeticity. +NativeLink doesn't currently integrate external sandboxing tools +like `bwrap`, `landlock`, or `sandbox-exec`. ## Toolchain The bundle of binaries an action needs to run — compiler, linker, -standard library, etc. See [What are toolchains?](/faq/toolchains). +standard library, etc. See +[how toolchains are provided](/rbe/examples#faq). diff --git a/web/apps/docs/content/docs/reference/nativelink-config/index.mdx b/web/apps/docs/content/docs/reference/nativelink-config/index.mdx index 62968266e..b5cd67761 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/index.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/index.mdx @@ -5,14 +5,14 @@ full: true --- {/* AUTOGENERATED — do not edit by hand. - Source: nativelink-config @ v1.5.2 (6e63ef9a) + Source: nativelink-config @ v1.6.4 (af3613e3) Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} -This is the canonical NativeLink configuration reference for **v1.5.2**. +This is the canonical NativeLink configuration reference for **v1.6.4**. It is autogenerated from the Rust config crate -([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src)) via the `build-schema` binary, so +([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.6.4/nativelink-config/src)) via the `build-schema` binary, so it can never drift from what the binary actually deserializes. ## Top-level fields @@ -151,8 +151,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -180,6 +180,55 @@ It supports the following backends: } ``` +5. **Cloudflare R2:** + R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + S3 API, so this is a thin wrapper that derives the account-scoped + endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + Storage API. The path-style endpoint is derived from your Object + Storage `namespace` and `region` as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + Authenticate with a Customer Secret Key (Access Key/Secret Key pair + created under User Settings -> Customer secret keys in the OCI + console); the secret cannot be retrieved after generation, so read + it from an env var via shellexpand. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + ``` + **Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) ### `ontap_s3_existence_cache` @@ -402,7 +451,7 @@ On uploads it will mirror data to both `fast` and `slow` stores. WARNING: If you need data to always exist in the `slow` store for something like remote execution, be careful because this store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes +`slow` store if it exists in the `fast` store (i.e. it assumes that if an object exists in the `fast` store it will exist in the `slow` store). @@ -503,7 +552,7 @@ in one store and large objects in another store. This should only be used if the size field is the real size of the content, in other words, don't use on AC (Action Cache) stores. Any store where you can safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). +to use (i.e. CAS stores). **Example JSON5 config:** ```json5 @@ -527,7 +576,7 @@ to use (i.e., CAS stores). ### `grpc` -This store will pass-through calls to another GRPC store. This store +This store will pass-through calls to another gRPC store. This store is not designed to be used as a sub-store of another store, but it does satisfy the interface and will likely work. @@ -569,6 +618,12 @@ Pairs well with `SizePartitioning` and/or `FastSlow` stores. Ideal for accepting small object sizes as most Redis store services have a max file upload of between 256Mb-512Mb. +If you are using Redis together with any stores above it +e.g. existence cache, you will need to configure `notify-keyspace-events` +to `KA` as per [https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/#configuration](https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/#configuration) +in order for us to get eviction events. Failing to do so will get you +log messages complaining about it, as well as errors like [https://github.com/TraceMachina/nativelink/issues/2436](https://github.com/TraceMachina/nativelink/issues/2436) + **Example JSON5 config:** ```json5 "redis_store": { @@ -688,7 +743,7 @@ Plus exactly one of the following variants (the key selects the variant): | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | -| `backend` | [StoreSpec](#storespec) | Yes | — | Store to wrap with cache operation metrics. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | ## MemorySpec @@ -712,7 +767,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -720,22 +775,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | @@ -745,16 +800,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | | `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | @@ -768,12 +823,13 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service startup this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | -| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e., move without copy). All files in this folder will be deleted on every startup. | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service boot this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e. move without copy). All files in this folder will be deleted on every startup. | | `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | | `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | | `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | +| `evict_page_cache` | boolean | — | false | When true, advise the kernel to drop the page cache for each blob after it is written or read (`posix_fadvise` with `POSIX_FADV_DONTNEED`). On real filesystems this takes a globally serialized, all-CPU kernel path that stalls on many-core hosts, and it evicts the page-cache tier that fast-disk deployments rely on. Leave off unless you specifically want to keep this store's I/O out of the page cache. | ## RefSpec @@ -786,23 +842,25 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `instance_name` | string | — | `""` | Instance name for GRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `instance_name` | string | — | `""` | Instance name for gRPC calls. Proxy calls will have the `instance_name` changed to this. | | `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | | `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | | `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | | `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | -| `connections_per_endpoint` | integer (uint) | — | `0` | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. Default 1. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | | `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | | `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | | `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | | `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | +| `experimental_read_batching` | [GrpcReadBatchingConfig](#grpcreadbatchingconfig) | — | unset (disabled) | Optional and experimental: coalesce small-blob reads into `BatchReadBlobs` RPCs instead of issuing one `ByteStream` `Read` stream per blob. Each `ByteStream` read carries a fixed per-RPC cost, so batching many small reads into a single `BatchReadBlobs` request can dramatically reduce read latency for small blobs. | +| `experimental_remote_cache_compression` | boolean | — | inherited from the process-wide zstd wire-compression intent | Compress this store's own blob transfers on the wire with REAPI `compressed-blobs/zstd`. Uploads and full-blob downloads of blobs at or above 64 KiB are zstd-compressed; smaller blobs and ranged reads keep the identity path. | ## RedisSpec @@ -820,7 +878,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | | `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | | `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | -| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it is a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it's a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | | `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | | `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | | `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | @@ -855,10 +913,12 @@ Configuration for `ExperimentalMongoDB` store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e., "{name}{uuidv6}"). | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e. "{name}{uuidv6}"). | | `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | -| `max_action_timeout` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | -| `max_upload_timeout` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_action_timeout_s` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | +| `max_upload_timeout_s` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. Value in seconds. | +| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. Value in milliseconds. | | `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | | `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | | `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | @@ -885,6 +945,7 @@ Configuration for `ExperimentalMongoDB` store. | `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | | `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | | `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | +| `fallback_match_interval_s` | integer (int64) | — | `5` | Every N seconds, run a worker matching pass even if no task or worker change notification arrived. This is a safety net for missed notifications and for scheduler backends with eventually consistent searches (for example Redis), where an operation that was re-queued may not be visible to the search triggered by its own notification. Without this, such an operation can stay queued until an unrelated event triggers another matching pass. Defaults to 5s. Zero or any negative value disables it. | ## SchedulerGrpcSpec @@ -940,7 +1001,7 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | --- | --- | --- | --- | --- | | `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | | `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | -| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel GRPC service. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel gRPC service. | | `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | | `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | | `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | @@ -970,702 +1031,133 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | | `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): +## EvictionPolicy -### `cache_metrics` +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. -Cache metrics store wraps another store and emits low-cardinality -OpenTelemetry cache operation metrics for the wrapped store. +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | -This wrapper is opt-in. Stores that are not explicitly wrapped by -`cache_metrics` are constructed exactly as they are without this -wrapper and do not pay its hot-path timing or recording cost. +## Retry -**Example JSON5 config:** -```json5 -"cache_metrics": { - "cache_type": "cas", - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-cas", - "temp_path": "~/.cache/nativelink/tmp_path-cas" - } - } +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, } ``` +will result in: -**Type:** [CacheMetricsSpec](#cachemetricsspec) +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | -### `memory` +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. -Memory store will store all data in a hash map in memory. +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this isn't set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` +## ExperimentalOntapS3Spec -**Type:** [MemorySpec](#memoryspec) +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -### `experimental_cloud_object_store` +## CompressionAlgorithm -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: +Plus exactly one of the following variants (the key selects the variant): -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. +### `lz4` - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +**Type:** [Lz4Config](#lz4config) -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. +## StoreDirection - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. +## ShardConfig - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` +Configuration for an individual shard of the store. - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) +## GrpcEndpoint -### `ontap_s3_existence_cache` +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. `grpc(s)://example.com:443`). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. +## StoreType -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` +## GrpcReadBatchingConfig -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) +Configuration for experimental small-blob read coalescing in a gRPC +store. See [`GrpcSpec::experimental_read_batching`]. -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - -## EvictionPolicy - -Eviction policy always works on LRU (Least Recently Used). Any time an entry -is touched it updates the timestamp. Inserts and updates will execute the -eviction policy removing any expired entries and/or the oldest entries -until the store size becomes smaller than `max_bytes`. - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | -| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | -| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | -| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | - -## Retry - -Retry configuration. This configuration is exponential and each iteration -a jitter as a percentage is applied of the calculated delay. For example: -```haskell -Retry{ - max_retries: 7, - delay: 0.1, - jitter: 0.5, -} -``` -will result in: - -| Attempt | Delay | -| --- | --- | -| 1 | 0 ms | -| 2 | 75 to 125 ms | -| 3 | 150 to 250 ms | -| 4 | 300 to 500 ms | -| 5 | 600 ms to 1 s | -| 6 | 1.2 to 2 s | -| 7 | 2.4 to 4 s | -| 8 | 4.8 to 8 s | - -The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | -| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | -| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | -| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this is not set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | - -## ExperimentalOntapS3Spec - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `endpoint` | string | Yes | — | | -| `vserver_name` | string | Yes | — | | -| `bucket` | string | Yes | — | | -| `root_certificates` | string | — | — | | -| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | -| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | -| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | -| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | -| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | -| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | -| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | - -## CompressionAlgorithm - -Plus exactly one of the following variants (the key selects the variant): - -### `lz4` - -LZ4 compression algorithm is extremely fast for compression and -decompression, however does not perform very well in compression -ratio. In most cases build artifacts are highly compressible, however -lz4 is quite good at aborting early if the data is not deemed very -compressible. - -see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) - -**Type:** [Lz4Config](#lz4config) - -## StoreDirection - -| Value | Description | -| --- | --- | -| `"both"` | The store operates normally and all get and put operations are handled by it. | -| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | -| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | -| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | - -## ShardConfig - -Configuration for an individual shard of the store. - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | -| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | - -## GrpcEndpoint - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `address` | string | Yes | — | The endpoint address (i.e. grpc://example.com:443 or grpcs://example.com:443). | -| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | -| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | -| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | -| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | -| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | -| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | - -## StoreType - -| Value | Description | -| --- | --- | -| `"cas"` | The store is content addressable storage. | -| `"ac"` | The store is an action cache. | +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_blob_size_bytes` | integer (uint64) | — | 131072 (128 KiB) | Only blobs at or below this size (in bytes) are eligible for batching. Larger blobs always use the `ByteStream` `Read` path. | +| `max_batch_bytes` | integer (uint64) | — | 3145728 (3 MiB) | Maximum total payload bytes packed into a single `BatchReadBlobs` request. This should leave headroom under the 4 MiB default gRPC message limit for protobuf framing overhead. | +| `dispatch_slots` | integer (uint) | — | 4 | Maximum number of concurrent `BatchReadBlobs` RPCs dispatched by the coalescer. Must be greater than zero. | +| `max_queued_bytes` | integer (uint64) | — | 33554432 (32 MiB) | Bound on the number of payload bytes waiting in the coalescer queue. When exceeded, new read requests bypass batching and fall back to the regular `ByteStream` `Read` path instead of blocking. | ## RedisMode @@ -1733,6 +1225,9 @@ One of: | `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | | `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | | `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | +| `experimental_subtree_caching` | boolean | — | false (only root directories are cached; existing behavior) | Optional and experimental: additionally cache every subdirectory by its own `Directory` digest, not just the root directory. REAPI Merkle nodes are content-addressed, so a subtree that is byte-identical between two different roots has the same digest and can be materialized with a single hardlink pass instead of being rebuilt from the CAS. This makes the common "one input file changed out of thousands" case reuse every unchanged subtree. | +| `max_concurrent_fetches` | integer (uint) | — | 64 | Maximum number of concurrent slow-store fetches across ALL directory constructions of this cache. This bound protects backing stores from RPC storms: per-level construction concurrency compounds multiplicatively across tree levels and concurrent actions. | +| `experimental_get_tree_prefetch` | boolean | — | false | On a directory-cache miss, prefetch every `Directory` proto of the tree with one logical `GetTree` traversal instead of fetching protos level by level (which costs one round trip per tree DEPTH). The [REAPI request contract] permits servers to impose their own limit even when no page size is specified, and the [REAPI response contract] requires clients to continue with the returned page token. A paginated traversal may therefore use multiple RPCs. Only takes effect when the slow tier is a `grpc` store; any prefetch failure falls back to the per-level path. Worthwhile when worker-to-CAS latency is non-trivial and trees are deep; measured 5-34x on the proto phase at 5-25ms RTT. Note the serving CAS pays the tree walk against its own backend, so its directory protos should be served from a fast tier. | ## PropertyType @@ -1827,6 +1322,7 @@ If a property is found, then replace it with another one. | --- | --- | --- | --- | --- | | `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | | `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `experimental_chunking` | [CasChunkingConfig](#caschunkingconfig) | — | not set — chunking RPCs are rejected, nothing is advertised, | Optional and experimental: enables the REAPI `SplitBlob`/`SpliceBlob` RPCs used by content-defined chunking clients (e.g. Bazel's `--experimental_remote_cache_chunking`). When set, the capabilities service advertises blob split/splice support and `FastCDC` 2020 parameters for this instance. When `cas_store` is a grpc store the RPCs are forwarded to the backend (which must support chunking with matching parameters); otherwise they are served locally. | ## ActionCacheServiceConfig @@ -1842,6 +1338,7 @@ If a property is found, then replace it with another one. | --- | --- | --- | --- | --- | | `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | | `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | +| `remote_cache_compression` | boolean | — | — | Whether this instance supports Bazel remote cache compression. When enabled, the capabilities service advertises zstd wire compression and the ByteStream/CAS services accept REAPI compressed-blobs/zstd data. | ## ExecutionServiceConfig @@ -1858,7 +1355,7 @@ If a property is found, then replace it with another one. | `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | | `cas_store` | string | Yes | — | Name of the store in the "stores" configuration. | | `max_bytes_per_stream` | integer (uint) | — | 64KiB | Max number of bytes to send on each grpc stream chunk. According to [https://github.com/grpc/grpc.github.io/issues/371](https://github.com/grpc/grpc.github.io/issues/371) 16KiB - 64KiB is optimal. | -| `persist_stream_on_disconnect_timeout` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | +| `persist_stream_on_disconnect_timeout_s` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | ## FetchServiceConfig @@ -2005,7 +1502,7 @@ specified. | `experimental_http2_adaptive_window` | boolean | — | — | | | `experimental_http2_max_frame_size` | integer (uint32) | — | — | | | `experimental_http2_max_concurrent_streams` | integer (uint32) | — | — | | -| `experimental_http2_keep_alive_timeout` | integer (uint32) | — | — | Note: This is in seconds. | +| `experimental_http2_keep_alive_timeout_s` | integer (uint32) | — | — | | | `experimental_http2_max_send_buf_size` | integer (uint32) | — | — | | | `experimental_http2_enable_connect_protocol` | boolean | — | — | | | `experimental_http2_max_header_list_size` | integer (uint32) | — | — | | @@ -2019,6 +1516,14 @@ specified. | `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | | `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | +## CasChunkingConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | string | — | — | The store name referenced in the `stores` map in the main config used to persist blob-to-chunks layouts. Keys are the digests of the original blobs and values are serialized chunk layouts (which do not hash to those digests), so this store MUST NOT perform content digest verification and MUST NOT be the same store as `cas_store` — writing layouts into the CAS would overwrite blob content. Using the same store name as `cas_store` is rejected at startup. | +| `avg_chunk_size_bytes` | integer (uint64) | — | 524288 (512 KiB) | The average chunk size in bytes advertised to clients through the `FastCDC` 2020 capability parameters and used for server-side chunking in `SplitBlob`. Clients derive the minimum and maximum chunk sizes from this value (avg / 4 and avg * 4). The value must be between 1 KiB and 1 MiB. | +| `max_chunk_count` | integer (uint64) | — | 50000 | Maximum number of chunks accepted in a `SpliceBlob` request or produced by on-demand chunking in `SplitBlob`. Blobs that would produce more chunks are served without chunking (`SplitBlob` returns `NOT_FOUND` and clients fall back to a regular download). This bounds the size of stored chunk layouts and of `SplitBlobResponse` messages (roughly 80-140 bytes per chunk). At the default average chunk size the default cap supports blobs up to ~25 GiB; note that values above ~50000 may produce responses that exceed default gRPC message size limits on clients. | + ## CapabilitiesRemoteExecutionConfig | Field | Type | Required | Default | Description | @@ -2036,6 +1541,6 @@ specified. If anything here disagrees with the binary, the source wins: -- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src/stores.rs) -- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src/cas_server.rs) -- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src/schedulers.rs) +- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.4/nativelink-config/src/stores.rs) +- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.4/nativelink-config/src/cas_server.rs) +- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.4/nativelink-config/src/schedulers.rs) diff --git a/web/apps/docs/content/docs/reference/nativelink-config/main.mdx b/web/apps/docs/content/docs/reference/nativelink-config/main.mdx index d8c56476f..40a36e803 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/main.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/main.mdx @@ -5,7 +5,7 @@ full: true --- {/* AUTOGENERATED — do not edit by hand. - Source: nativelink-config @ main (cfb8141e) + Source: nativelink-config @ main (64ca9740) Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} @@ -151,8 +151,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -180,6 +180,55 @@ It supports the following backends: } ``` +5. **Cloudflare R2:** + R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + S3 API, so this is a thin wrapper that derives the account-scoped + endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + Storage API. The path-style endpoint is derived from your Object + Storage `namespace` and `region` as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + Authenticate with a Customer Secret Key (Access Key/Secret Key pair + created under User Settings -> Customer secret keys in the OCI + console); the secret cannot be retrieved after generation, so read + it from an env var via shellexpand. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + ``` + **Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) ### `ontap_s3_existence_cache` @@ -402,7 +451,7 @@ On uploads it will mirror data to both `fast` and `slow` stores. WARNING: If you need data to always exist in the `slow` store for something like remote execution, be careful because this store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes +`slow` store if it exists in the `fast` store (i.e. it assumes that if an object exists in the `fast` store it will exist in the `slow` store). @@ -503,7 +552,7 @@ in one store and large objects in another store. This should only be used if the size field is the real size of the content, in other words, don't use on AC (Action Cache) stores. Any store where you can safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). +to use (i.e. CAS stores). **Example JSON5 config:** ```json5 @@ -527,7 +576,7 @@ to use (i.e., CAS stores). ### `grpc` -This store will pass-through calls to another GRPC store. This store +This store will pass-through calls to another gRPC store. This store is not designed to be used as a sub-store of another store, but it does satisfy the interface and will likely work. @@ -569,6 +618,12 @@ Pairs well with `SizePartitioning` and/or `FastSlow` stores. Ideal for accepting small object sizes as most Redis store services have a max file upload of between 256Mb-512Mb. +If you are using Redis together with any stores above it +e.g. existence cache, you will need to configure `notify-keyspace-events` +to `KA` as per [https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/#configuration](https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/#configuration) +in order for us to get eviction events. Failing to do so will get you +log messages complaining about it, as well as errors like [https://github.com/TraceMachina/nativelink/issues/2436](https://github.com/TraceMachina/nativelink/issues/2436) + **Example JSON5 config:** ```json5 "redis_store": { @@ -688,7 +743,7 @@ Plus exactly one of the following variants (the key selects the variant): | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | -| `backend` | [StoreSpec](#storespec) | Yes | — | Store to wrap with cache operation metrics. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | ## MemorySpec @@ -712,7 +767,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -720,22 +775,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | @@ -745,16 +800,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | | `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | @@ -768,12 +823,13 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service startup this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | -| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e., move without copy). All files in this folder will be deleted on every startup. | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service boot this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e. move without copy). All files in this folder will be deleted on every startup. | | `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | | `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | | `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | +| `evict_page_cache` | boolean | — | false | When true, advise the kernel to drop the page cache for each blob after it is written or read (`posix_fadvise` with `POSIX_FADV_DONTNEED`). On real filesystems this takes a globally serialized, all-CPU kernel path that stalls on many-core hosts, and it evicts the page-cache tier that fast-disk deployments rely on. Leave off unless you specifically want to keep this store's I/O out of the page cache. | ## RefSpec @@ -786,23 +842,25 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `instance_name` | string | — | `""` | Instance name for GRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `instance_name` | string | — | `""` | Instance name for gRPC calls. Proxy calls will have the `instance_name` changed to this. | | `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | | `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | | `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | | `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | -| `connections_per_endpoint` | integer (uint) | — | `0` | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. Default 1. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | | `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | | `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | | `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | | `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | +| `experimental_read_batching` | [GrpcReadBatchingConfig](#grpcreadbatchingconfig) | — | unset (disabled) | Optional and experimental: coalesce small-blob reads into `BatchReadBlobs` RPCs instead of issuing one `ByteStream` `Read` stream per blob. Each `ByteStream` read carries a fixed per-RPC cost, so batching many small reads into a single `BatchReadBlobs` request can dramatically reduce read latency for small blobs. | +| `experimental_remote_cache_compression` | boolean | — | inherited from the process-wide zstd wire-compression intent | Compress this store's own blob transfers on the wire with REAPI `compressed-blobs/zstd`. Uploads and full-blob downloads of blobs at or above 64 KiB are zstd-compressed; smaller blobs and ranged reads keep the identity path. | ## RedisSpec @@ -820,7 +878,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | | `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | | `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | -| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it is a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it's a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | | `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | | `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | | `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | @@ -855,12 +913,12 @@ Configuration for `ExperimentalMongoDB` store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e., "{name}{uuidv6}"). | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e. "{name}{uuidv6}"). | | `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | | `max_action_timeout_s` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | | `max_upload_timeout_s` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | -| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. When an action completes, the worker waits for the directory to be cleaned up before reusing it. If cleanup takes longer than this, the action fails with `DeadlineExceeded`. Value in seconds. | -| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. When waiting for a previous operation's cleanup to complete, the worker uses exponential backoff starting from a small value and increasing up to this maximum. Value in milliseconds. | +| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. Value in seconds. | +| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. Value in milliseconds. | | `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | | `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | | `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | @@ -887,6 +945,7 @@ Configuration for `ExperimentalMongoDB` store. | `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | | `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | | `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | +| `fallback_match_interval_s` | integer (int64) | — | `5` | Every N seconds, run a worker matching pass even if no task or worker change notification arrived. This is a safety net for missed notifications and for scheduler backends with eventually consistent searches (for example Redis), where an operation that was re-queued may not be visible to the search triggered by its own notification. Without this, such an operation can stay queued until an unrelated event triggers another matching pass. Defaults to 5s. Zero or any negative value disables it. | ## SchedulerGrpcSpec @@ -942,7 +1001,7 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | --- | --- | --- | --- | --- | | `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | | `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | -| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel GRPC service. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel gRPC service. | | `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | | `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | | `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | @@ -972,702 +1031,133 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | | `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): +## EvictionPolicy -### `cache_metrics` +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. -Cache metrics store wraps another store and emits low-cardinality -OpenTelemetry cache operation metrics for the wrapped store. +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | -This wrapper is opt-in. Stores that are not explicitly wrapped by -`cache_metrics` are constructed exactly as they are without this -wrapper and do not pay its hot-path timing or recording cost. +## Retry -**Example JSON5 config:** -```json5 -"cache_metrics": { - "cache_type": "cas", - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-cas", - "temp_path": "~/.cache/nativelink/tmp_path-cas" - } - } +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, } ``` +will result in: -**Type:** [CacheMetricsSpec](#cachemetricsspec) +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | -### `memory` +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. -Memory store will store all data in a hash map in memory. +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this isn't set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` +## ExperimentalOntapS3Spec -**Type:** [MemorySpec](#memoryspec) +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -### `experimental_cloud_object_store` +## CompressionAlgorithm -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: +Plus exactly one of the following variants (the key selects the variant): -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. +### `lz4` - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +**Type:** [Lz4Config](#lz4config) -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. +## StoreDirection - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. +## ShardConfig - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` +Configuration for an individual shard of the store. - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) +## GrpcEndpoint -### `ontap_s3_existence_cache` +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. `grpc(s)://example.com:443`). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. +## StoreType -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` +## GrpcReadBatchingConfig -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) +Configuration for experimental small-blob read coalescing in a gRPC +store. See [`GrpcSpec::experimental_read_batching`]. -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - -## EvictionPolicy - -Eviction policy always works on LRU (Least Recently Used). Any time an entry -is touched it updates the timestamp. Inserts and updates will execute the -eviction policy removing any expired entries and/or the oldest entries -until the store size becomes smaller than `max_bytes`. - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | -| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | -| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | -| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | - -## Retry - -Retry configuration. This configuration is exponential and each iteration -a jitter as a percentage is applied of the calculated delay. For example: -```haskell -Retry{ - max_retries: 7, - delay: 0.1, - jitter: 0.5, -} -``` -will result in: - -| Attempt | Delay | -| --- | --- | -| 1 | 0 ms | -| 2 | 75 to 125 ms | -| 3 | 150 to 250 ms | -| 4 | 300 to 500 ms | -| 5 | 600 ms to 1 s | -| 6 | 1.2 to 2 s | -| 7 | 2.4 to 4 s | -| 8 | 4.8 to 8 s | - -The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | -| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | -| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | -| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this is not set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | - -## ExperimentalOntapS3Spec - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `endpoint` | string | Yes | — | | -| `vserver_name` | string | Yes | — | | -| `bucket` | string | Yes | — | | -| `root_certificates` | string | — | — | | -| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | -| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | -| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | -| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | -| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | -| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | -| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | - -## CompressionAlgorithm - -Plus exactly one of the following variants (the key selects the variant): - -### `lz4` - -LZ4 compression algorithm is extremely fast for compression and -decompression, however does not perform very well in compression -ratio. In most cases build artifacts are highly compressible, however -lz4 is quite good at aborting early if the data is not deemed very -compressible. - -see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) - -**Type:** [Lz4Config](#lz4config) - -## StoreDirection - -| Value | Description | -| --- | --- | -| `"both"` | The store operates normally and all get and put operations are handled by it. | -| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | -| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | -| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | - -## ShardConfig - -Configuration for an individual shard of the store. - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | -| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | - -## GrpcEndpoint - -| Field | Type | Required | Default | Description | -| --- | --- | --- | --- | --- | -| `address` | string | Yes | — | The endpoint address (i.e. grpc://example.com:443 or grpcs://example.com:443). | -| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | -| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | -| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | -| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | -| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | -| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | - -## StoreType - -| Value | Description | -| --- | --- | -| `"cas"` | The store is content addressable storage. | -| `"ac"` | The store is an action cache. | +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_blob_size_bytes` | integer (uint64) | — | 131072 (128 KiB) | Only blobs at or below this size (in bytes) are eligible for batching. Larger blobs always use the `ByteStream` `Read` path. | +| `max_batch_bytes` | integer (uint64) | — | 3145728 (3 MiB) | Maximum total payload bytes packed into a single `BatchReadBlobs` request. This should leave headroom under the 4 MiB default gRPC message limit for protobuf framing overhead. | +| `dispatch_slots` | integer (uint) | — | 4 | Maximum number of concurrent `BatchReadBlobs` RPCs dispatched by the coalescer. Must be greater than zero. | +| `max_queued_bytes` | integer (uint64) | — | 33554432 (32 MiB) | Bound on the number of payload bytes waiting in the coalescer queue. When exceeded, new read requests bypass batching and fall back to the regular `ByteStream` `Read` path instead of blocking. | ## RedisMode @@ -1735,6 +1225,9 @@ One of: | `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | | `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | | `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | +| `experimental_subtree_caching` | boolean | — | false (only root directories are cached; existing behavior) | Optional and experimental: additionally cache every subdirectory by its own `Directory` digest, not just the root directory. REAPI Merkle nodes are content-addressed, so a subtree that is byte-identical between two different roots has the same digest and can be materialized with a single hardlink pass instead of being rebuilt from the CAS. This makes the common "one input file changed out of thousands" case reuse every unchanged subtree. | +| `max_concurrent_fetches` | integer (uint) | — | 64 | Maximum number of concurrent slow-store fetches across ALL directory constructions of this cache. This bound protects backing stores from RPC storms: per-level construction concurrency compounds multiplicatively across tree levels and concurrent actions. | +| `experimental_get_tree_prefetch` | boolean | — | false | On a directory-cache miss, prefetch every `Directory` proto of the tree with one logical `GetTree` traversal instead of fetching protos level by level (which costs one round trip per tree DEPTH). The [REAPI request contract] permits servers to impose their own limit even when no page size is specified, and the [REAPI response contract] requires clients to continue with the returned page token. A paginated traversal may therefore use multiple RPCs. Only takes effect when the slow tier is a `grpc` store; any prefetch failure falls back to the per-level path. Worthwhile when worker-to-CAS latency is non-trivial and trees are deep; measured 5-34x on the proto phase at 5-25ms RTT. Note the serving CAS pays the tree walk against its own backend, so its directory protos should be served from a fast tier. | ## PropertyType @@ -1829,6 +1322,7 @@ If a property is found, then replace it with another one. | --- | --- | --- | --- | --- | | `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | | `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `experimental_chunking` | [CasChunkingConfig](#caschunkingconfig) | — | not set — chunking RPCs are rejected, nothing is advertised, | Optional and experimental: enables the REAPI `SplitBlob`/`SpliceBlob` RPCs used by content-defined chunking clients (e.g. Bazel's `--experimental_remote_cache_chunking`). When set, the capabilities service advertises blob split/splice support and `FastCDC` 2020 parameters for this instance. When `cas_store` is a grpc store the RPCs are forwarded to the backend (which must support chunking with matching parameters); otherwise they are served locally. | ## ActionCacheServiceConfig @@ -1844,6 +1338,7 @@ If a property is found, then replace it with another one. | --- | --- | --- | --- | --- | | `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | | `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | +| `remote_cache_compression` | boolean | — | — | Whether this instance supports Bazel remote cache compression. When enabled, the capabilities service advertises zstd wire compression and the ByteStream/CAS services accept REAPI compressed-blobs/zstd data. | ## ExecutionServiceConfig @@ -2021,6 +1516,14 @@ specified. | `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | | `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | +## CasChunkingConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | string | — | — | The store name referenced in the `stores` map in the main config used to persist blob-to-chunks layouts. Keys are the digests of the original blobs and values are serialized chunk layouts (which do not hash to those digests), so this store MUST NOT perform content digest verification and MUST NOT be the same store as `cas_store` — writing layouts into the CAS would overwrite blob content. Using the same store name as `cas_store` is rejected at startup. | +| `avg_chunk_size_bytes` | integer (uint64) | — | 524288 (512 KiB) | The average chunk size in bytes advertised to clients through the `FastCDC` 2020 capability parameters and used for server-side chunking in `SplitBlob`. Clients derive the minimum and maximum chunk sizes from this value (avg / 4 and avg * 4). The value must be between 1 KiB and 1 MiB. | +| `max_chunk_count` | integer (uint64) | — | 50000 | Maximum number of chunks accepted in a `SpliceBlob` request or produced by on-demand chunking in `SplitBlob`. Blobs that would produce more chunks are served without chunking (`SplitBlob` returns `NOT_FOUND` and clients fall back to a regular download). This bounds the size of stored chunk layouts and of `SplitBlobResponse` messages (roughly 80-140 bytes per chunk). At the default average chunk size the default cap supports blobs up to ~25 GiB; note that values above ~50000 may produce responses that exceed default gRPC message size limits on clients. | + ## CapabilitiesRemoteExecutionConfig | Field | Type | Required | Default | Description | diff --git a/web/apps/docs/content/docs/reference/nativelink-config/meta.json b/web/apps/docs/content/docs/reference/nativelink-config/meta.json index 35333832f..22e3bb1a6 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/meta.json +++ b/web/apps/docs/content/docs/reference/nativelink-config/meta.json @@ -1,6 +1,7 @@ { "pages": [ - "index" + "index", + "store-overview" ], "title": "NativeLink config" } diff --git a/web/apps/docs/content/docs/reference/nativelink-config/store-overview.mdx b/web/apps/docs/content/docs/reference/nativelink-config/store-overview.mdx new file mode 100644 index 000000000..81637daf1 --- /dev/null +++ b/web/apps/docs/content/docs/reference/nativelink-config/store-overview.mdx @@ -0,0 +1,191 @@ +--- +title: Store overview +description: The mental model behind every store in the configuration reference — what holds data, what wraps another store, and how they compose. +--- + +The [full reference](/reference/nativelink-config) lists every field on +every store. This page is the map you need before that list is useful: +what a store actually is, the two families every store falls into, and +the compositions people actually run in production. + +## What a store is + +A store is a named, pluggable backend for CAS or AC data. You declare +each one once in the top-level `stores` array, then reference it by +name from `servers`, `workers`, or from inside another store: + +```json5 +{ + stores: [ + { name: "CAS_MAIN_STORE", filesystem: { /* ... */ } }, + ], + servers: [{ + services: { + cas: [{ instance_name: "main", cas_store: "CAS_MAIN_STORE" }], + }, + }], +} +``` + +The store's *type* is whichever key you put inside its object — +`filesystem`, `memory`, `compression`, `fast_slow`, and so on. NativeLink +picks the implementation from that key; everything else in the object is +that implementation's config. + +## Two families + +Every store type is either **terminal** (it actually holds or fetches +bytes) or a **wrapper** (it adds behavior in front of another store, +which it embeds as a nested `StoreSpec`). Wrappers nest arbitrarily +deep — a `verify` can wrap a `compression`, which wraps a `fast_slow`, +which wraps two more terminal stores: + + +{`flowchart LR + V["verify\\n(hash + size check)"] --> C["compression\\n(lz4)"] + C --> F["fast_slow"] + F -->|fast| M[("memory")] + F -->|slow| D[("filesystem")]`} + + +Reads and writes flow through every wrapper in order. Nothing about the +client changes — it still speaks plain CAS/AC RPCs against whatever +store name the server exposes. + +### Terminal stores — where bytes actually live + +| Store key | Holds data in | Notes | +| --- | --- | --- | +| `memory` | An in-process hash map | Fastest, gone on restart. Good for AC tiers and dev. | +| `filesystem` | Local disk | Survives restarts; scans and rebuilds its index on startup. | +| `experimental_cloud_object_store` | A cloud object bucket | One store type, six `provider`s: `aws` (S3), `gcs`, `azure`, `ontap` (NetApp ONTAP S3), `r2` (Cloudflare), `oci` (Oracle Cloud Infrastructure). All speak an S3-compatible API except `gcs` and `azure`. | +| `redis_store` | Any Redis-API-compatible service | Pairs well with `size_partitioning` — most Redis services cap uploads around 256–512 MB. | +| `experimental_mongo` | MongoDB | Supports CAS and scheduler data, with optional change streams for scheduler subscriptions. | +| `grpc` | Another NativeLink-compatible gRPC endpoint | Proxies calls upstream. Useful for a regional cache in front of a central cluster. | +| `ref_store` | Nothing itself — points at another store by name | Lets two composition trees share one underlying store instance (see below). | +| `noop` | Nothing | Reads 404. Writes vanish. Used to explicitly discard a partition of data. | + +### Wrapper stores — behavior layered on a backend + +| Store key | Wraps | What it adds | +| --- | --- | --- | +| `compression` | one store | LZ4-compresses on write, decompresses on read. | +| `dedup` | two stores (`index_store` + `content_store`) | Rolling-hash chunking so only changed slices upload. | +| `fast_slow` | two stores (`fast` + `slow`) | Reads try `fast` first, fall back to `slow`, and backfill `fast`. Writes mirror to both. | +| `shard` | N stores | Routes by digest hash. The standard shape for scaling CAS past one backend. | +| `size_partitioning` | two stores (`lower_store` + `upper_store`) | Routes by blob size instead of hash. CAS-only — see the gotcha below. | +| `verify` | one store | Rejects uploads that fail a hash and/or size check before they ever reach the backend. | +| `existence_cache` | one store | Caches `has()` results. CAS-only. | +| `completeness_checking` | one store + a CAS store | Confirms an `ActionResult`'s output digests exist in CAS before returning it. AC-only. | +| `cache_metrics` | one store | Emits OpenTelemetry cache-hit/miss metrics for the wrapped store. Opt-in — stores you don't wrap pay nothing extra. | +| `ontap_s3_existence_cache` | (built-in ONTAP S3 backend) | Purpose-built existence cache for ONTAP S3 specifically, with disk-persisted sync instead of a generic wrapped backend. | + + + - Put `dedup` *inside* `compression` (compression wraps dedup's output), + never the other way — `compression` as `dedup`'s `content_store` negates + dedup's gains, since every chunk becomes a differently-compressed blob. + - `fast_slow` never checks whether an object in `fast` also exists in + `slow`. If you need a durability guarantee — e.g. remote execution + artifacts that must survive a `fast`-tier wipe — write-through both + tiers deliberately rather than assuming it. + - `existence_cache` and `size_partitioning` are CAS-only; `completeness_checking` + is AC-only. Using them on the other store type produces confusing + correctness bugs, not a config error. + + +## Choosing a terminal backend + +| Backend | Durability | Shared across instances | Typical role | +| --- | --- | --- | --- | +| `memory` | None (restart wipes it) | No | Fast tier in a `fast_slow`, or a whole AC store for a short-lived CI runner. | +| `filesystem` | Survives restarts | No (single node) | Single-node dev/CI cache, or the fast/local tier in front of shared storage. | +| `experimental_cloud_object_store` | Durable, provider-managed | Yes | The shared, multi-node backing store in most production clusters. | +| `redis_store` | As durable as your Redis deployment | Yes | Low-latency shared tier, usually fronted by `size_partitioning` to keep large blobs out of it. | +| `experimental_mongo` | Durable | Yes | Alternative shared backend when you already operate MongoDB and want scheduler-state change streams. | + +## Common compositions + +**Single-node dev cache** — no wrapping at all. See +[Configuration → Basic](/configuration/basic). + +**Validated, compressed, tiered CAS** — the shape most self-hosted +production clusters converge on: + +```json5 +{ + name: "CAS_MAIN_STORE", + verify: { + verify_size: true, + verify_hash: true, + backend: { + compression: { + compression_algorithm: { lz4: {} }, + backend: { + fast_slow: { + fast: { memory: { eviction_policy: { max_bytes: "2gb" } } }, + slow: { + experimental_cloud_object_store: { + provider: "aws", + region: "us-east-1", + bucket: "nativelink-cas", + }, + }, + }, + }, + }, + }, + }, +} +``` + +**Sharing one store instance across two trees** — use `ref_store` +instead of declaring the same backend twice: + +```json5 +{ + stores: [ + { + name: "FS_CONTENT_STORE", + filesystem: { content_path: "/var/lib/nativelink/cas", temp_path: "/var/lib/nativelink/tmp" }, + }, + { + // The worker's fast/local tier and the AC's fast tier now share + // one filesystem store instead of each scanning their own copy. + name: "AC_MAIN_STORE", + fast_slow: { + fast: { ref_store: { name: "FS_CONTENT_STORE" } }, + slow: { noop: {} }, + }, + }, + ], +} +``` + +## FAQ + + + + No — it never checks that an object in `fast` also made it to `slow`. + If an artifact must survive a fast-tier wipe, make sure the write + path covers both tiers deliberately. + + + Redis caps uploads at roughly 256-512 MB. Route large blobs to a + disk- or object-store backend with `size_partitioning` and keep Redis + serving the small, hot objects it's good at. + + + `existence_cache` and `size_partitioning` are CAS-only; + `completeness_checking` is AC-only. Misplacing one isn't a config + error — it surfaces as a confusing correctness bug. + + + +## What's next + +- [Configuration reference](/reference/nativelink-config) — every + field, default, and JSON5 example for every store type above. +- [Configuration → Introduction](/configuration/intro) — how stores + fit alongside servers, schedulers, and workers. +- [Configuration → Production](/configuration/production) — sharded, + multi-region store topologies end to end. diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.0.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.0.0.mdx index cc4e46aca..f377ea362 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.0.0.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.0.0.mdx @@ -127,8 +127,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -667,7 +667,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -675,22 +675,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -700,16 +700,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -740,8 +740,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -970,553 +970,6 @@ The total delay is additive, so this example produces 9.525 to 15.875 s of total | `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | | `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac" -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## CompressionAlgorithm Plus exactly one of the following variants (the key selects the variant): @@ -1548,7 +1001,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.1.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.1.0.mdx index 410d1a6b1..a1abfdf37 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.1.0.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.1.0.mdx @@ -127,8 +127,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -677,7 +677,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -685,22 +685,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -710,16 +710,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -750,8 +750,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -986,563 +986,6 @@ The total delay is additive, so this example produces 9.525 to 15.875 s of total | `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | | `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## CompressionAlgorithm Plus exactly one of the following variants (the key selects the variant): @@ -1574,7 +1017,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.2.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.2.0.mdx index b25c586b0..878fb9b56 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.2.0.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.2.0.mdx @@ -127,8 +127,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -677,7 +677,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -685,22 +685,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -710,16 +710,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -750,8 +750,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -986,563 +986,6 @@ The total delay is additive, so this example produces 9.525 to 15.875 s of total | `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | | `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## CompressionAlgorithm Plus exactly one of the following variants (the key selects the variant): @@ -1574,7 +1017,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.3.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.3.0.mdx index 7cb96983f..f4840aff0 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.3.0.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.3.0.mdx @@ -127,8 +127,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -677,7 +677,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -685,22 +685,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -710,16 +710,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -750,8 +750,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -987,563 +987,6 @@ The total delay is additive, so this example produces 9.525 to 15.875 s of total | `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | | `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## CompressionAlgorithm Plus exactly one of the following variants (the key selects the variant): @@ -1575,7 +1018,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.3.1.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.3.1.mdx index 24c1f5891..2ccf26b6a 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.3.1.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.3.1.mdx @@ -127,8 +127,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -677,7 +677,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -685,22 +685,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -710,16 +710,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -750,8 +750,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -987,563 +987,6 @@ The total delay is additive, so this example produces 9.525 to 15.875 s of total | `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | | `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## CompressionAlgorithm Plus exactly one of the following variants (the key selects the variant): @@ -1575,7 +1018,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.3.2.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.3.2.mdx index 27bf375fa..5a78887b6 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.3.2.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.3.2.mdx @@ -151,8 +151,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -684,7 +684,7 @@ Plus exactly one of the following variants (the key selects the variant): | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | -| `backend` | [StoreSpec](#storespec) | Yes | — | Store to wrap with cache operation metrics. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | ## MemorySpec @@ -708,7 +708,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -716,22 +716,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -741,16 +741,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -781,8 +781,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -955,587 +955,6 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | | `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `cache_metrics` - -Cache metrics store wraps another store and emits low-cardinality -OpenTelemetry cache operation metrics for the wrapped store. - -This wrapper is opt-in. Stores that are not explicitly wrapped by -`cache_metrics` are constructed exactly as they are without this -wrapper and do not pay its hot-path timing or recording cost. - -**Example JSON5 config:** -```json5 -"cache_metrics": { - "cache_type": "cas", - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-cas", - "temp_path": "~/.cache/nativelink/tmp_path-cas" - } - } -} -``` - -**Type:** [CacheMetricsSpec](#cachemetricsspec) - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## EvictionPolicy Eviction policy always works on LRU (Least Recently Used). Any time an entry @@ -1630,7 +1049,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.4.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.4.0.mdx index 789716942..a5f3844f6 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.4.0.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.4.0.mdx @@ -151,8 +151,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -688,7 +688,7 @@ Plus exactly one of the following variants (the key selects the variant): | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | -| `backend` | [StoreSpec](#storespec) | Yes | — | Store to wrap with cache operation metrics. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | ## MemorySpec @@ -712,7 +712,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -720,22 +720,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -745,16 +745,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | ## ShardSpec @@ -785,8 +785,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -969,587 +969,6 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | | `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `cache_metrics` - -Cache metrics store wraps another store and emits low-cardinality -OpenTelemetry cache operation metrics for the wrapped store. - -This wrapper is opt-in. Stores that are not explicitly wrapped by -`cache_metrics` are constructed exactly as they are without this -wrapper and do not pay its hot-path timing or recording cost. - -**Example JSON5 config:** -```json5 -"cache_metrics": { - "cache_type": "cas", - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-cas", - "temp_path": "~/.cache/nativelink/tmp_path-cas" - } - } -} -``` - -**Type:** [CacheMetricsSpec](#cachemetricsspec) - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## EvictionPolicy Eviction policy always works on LRU (Least Recently Used). Any time an entry @@ -1644,7 +1063,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.5.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.5.0.mdx index f83656b30..49ceb05cd 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.5.0.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.5.0.mdx @@ -151,8 +151,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -688,7 +688,7 @@ Plus exactly one of the following variants (the key selects the variant): | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | -| `backend` | [StoreSpec](#storespec) | Yes | — | Store to wrap with cache operation metrics. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | ## MemorySpec @@ -712,7 +712,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -720,22 +720,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -745,16 +745,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | | `bypass_dedup_threshold_bytes` | integer (uint64) | — | `0` | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | @@ -786,8 +786,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -970,587 +970,6 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | | `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `cache_metrics` - -Cache metrics store wraps another store and emits low-cardinality -OpenTelemetry cache operation metrics for the wrapped store. - -This wrapper is opt-in. Stores that are not explicitly wrapped by -`cache_metrics` are constructed exactly as they are without this -wrapper and do not pay its hot-path timing or recording cost. - -**Example JSON5 config:** -```json5 -"cache_metrics": { - "cache_type": "cas", - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-cas", - "temp_path": "~/.cache/nativelink/tmp_path-cas" - } - } -} -``` - -**Type:** [CacheMetricsSpec](#cachemetricsspec) - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## EvictionPolicy Eviction policy always works on LRU (Least Recently Used). Any time an entry @@ -1645,7 +1064,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.5.1.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.5.1.mdx index 998dc3d6e..c4e5d43d1 100644 --- a/web/apps/docs/content/docs/reference/nativelink-config/v1.5.1.mdx +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.5.1.mdx @@ -151,8 +151,8 @@ It supports the following backends: } ``` -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend to store files. This store is specifically configured for ONTAP's S3 requirements including custom TLS configuration, credentials management, and proper vserver configuration. @@ -688,7 +688,7 @@ Plus exactly one of the following variants (the key selects the variant): | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | -| `backend` | [StoreSpec](#storespec) | Yes | — | Store to wrap with cache operation metrics. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | ## MemorySpec @@ -712,7 +712,7 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | | `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | @@ -720,22 +720,22 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store that will have it's results validated before sending to client. | -| `cas_store` | [StoreSpec](#storespec) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | ## CompressionSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | ## DedupSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `index_store` | [StoreSpec](#storespec) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | -| `content_store` | [StoreSpec](#storespec) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | | `min_size` | integer (uint32) | — | 65536 (64k) | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | | `normal_size` | integer (uint32) | — | 262144 (256k) | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | | `max_size` | integer (uint32) | — | 524288 (512k) | Maximum size a chunk is allowed to be. | @@ -745,16 +745,16 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `backend` | [StoreSpec](#storespec) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | | `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | ## FastSlowSpec | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `fast` | [StoreSpec](#storespec) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | | `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | -| `slow` | [StoreSpec](#storespec) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | | `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | | `bypass_dedup_threshold_bytes` | integer (uint64) | — | `0` | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | @@ -786,8 +786,8 @@ See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `size` | integer (uint64) | Yes | — | Size to partition the data on. | -| `lower_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is < (less than) size. | -| `upper_store` | [StoreSpec](#storespec) | Yes | — | Store to send data when object is >= (less than eq) size. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | ## GrpcSpec @@ -970,587 +970,6 @@ Listener for HTTP/HTTPS/HTTP2 sockets. | `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | | `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | -## StoreSpec - -Plus exactly one of the following variants (the key selects the variant): - -### `cache_metrics` - -Cache metrics store wraps another store and emits low-cardinality -OpenTelemetry cache operation metrics for the wrapped store. - -This wrapper is opt-in. Stores that are not explicitly wrapped by -`cache_metrics` are constructed exactly as they are without this -wrapper and do not pay its hot-path timing or recording cost. - -**Example JSON5 config:** -```json5 -"cache_metrics": { - "cache_type": "cas", - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-cas", - "temp_path": "~/.cache/nativelink/tmp_path-cas" - } - } -} -``` - -**Type:** [CacheMetricsSpec](#cachemetricsspec) - -### `memory` - -Memory store will store all data in a hash map in memory. - -**Example JSON5 config:** -```json5 -"memory": { - "eviction_policy": { - "max_bytes": "10mb", - } -} -``` - -**Type:** [MemorySpec](#memoryspec) - -### `experimental_cloud_object_store` - -A generic blob store that will store files on the cloud -provider. This configuration will never delete files, so you are -responsible for purging old files in other ways. -It supports the following backends: - -1. **Amazon S3:** - S3 store will use Amazon's S3 service as a backend to store - the files. This configuration can be used to share files - across multiple instances. Uses system certificates for TLS - verification via `rustls-platform-verifier`. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "aws", - "region": "eu-north-1", - "bucket": "crossplane-bucket-af79aeca9", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -2. **Google Cloud Storage:** - GCS store uses Google's GCS service as a backend to store - the files. This configuration can be used to share files - across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "gcs", - "bucket": "test-bucket", - "key_prefix": "test-prefix-index/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -3. **Azure Blob Store:** - Azure Blob store will use Microsoft's Azure Blob service as a - backend to store the files. This configuration can be used to - share files across multiple instances. - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "azure", - "account_name": "cloudshell1393657559", - "container": "simple-test-container", - "key_prefix": "folder/", - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -4. **`NetApp` ONTAP S3** - `NetApp` ONTAP S3 store will use ONTAP's S3-compatible storage as a backend - to store files. This store is specifically configured for ONTAP's S3 requirements - including custom TLS configuration, credentials management, and proper vserver - configuration. - - This store uses AWS environment variables for credentials: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` - - `AWS_DEFAULT_REGION` - - **Example JSON5 config:** - ```json5 - "experimental_cloud_object_store": { - "provider": "ontap", - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "root_certificates": "/path/to/certs.pem", // Optional - "key_prefix": "test-prefix/", // Optional - "retry": { - "max_retries": 6, - "delay": 0.3, - "jitter": 0.5 - }, - "multipart_max_concurrent_uploads": 10 - } - ``` - -**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) - -### `ontap_s3_existence_cache` - -ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store -to optimize repeated existence checks. It maintains an in-memory cache of object -digests and periodically syncs this cache to disk for persistence. - -The cache helps reduce latency for repeated calls to check object existence, -while still ensuring eventual consistency with the underlying ONTAP S3 store. - -Example JSON5 config: -```json5 -"ontap_s3_existence_cache": { - "index_path": "/path/to/cache/index.json", - "sync_interval_seconds": 300, - "backend": { - "endpoint": "https://ontap-s3-endpoint:443", - "vserver_name": "your-vserver", - "bucket": "your-bucket", - "key_prefix": "test-prefix/" - } -} -``` - -**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) - -### `verify` - -Verify store is used to apply verifications to an underlying -store implementation. It is strongly encouraged to validate -as much data as you can before accepting data from a client, -failing to do so may cause the data in the store to be -populated with invalid data causing all kinds of problems. - -The suggested configuration is to have the CAS validate the -hash and size and the AC validate nothing. - -**Example JSON5 config:** -```json5 -"verify": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb" - } - }, - }, - "verify_size": true, - "verify_hash": true -} -``` - -**Type:** [VerifySpec](#verifyspec) - -### `completeness_checking` - -Completeness checking store verifies if the -output files & folders exist in the CAS before forwarding -the request to the underlying store. -Note: This store should only be used on AC stores. - -**Example JSON5 config:** -```json5 -"completeness_checking": { - "backend": { - "filesystem": { - "content_path": "~/.cache/nativelink/content_path-ac", - "temp_path": "~/.cache/nativelink/tmp_path-ac", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "cas_store": { - "ref_store": { - "name": "CAS_MAIN_STORE" - } - } -} -``` - -**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) - -### `compression` - -A compression store that will compress the data inbound and -outbound. There will be a non-trivial cost to compress and -decompress the data, but in many cases if the final store is -a store that requires network transport and/or storage space -is a concern it is often faster and more efficient to use this -store before those stores. - -**Example JSON5 config:** -```json5 -"compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-cas", - "temp_path": "/tmp/nativelink/data/tmp_path-cas", - "eviction_policy": { - "max_bytes": "2gb", - } - } - } -} -``` - -**Type:** [CompressionSpec](#compressionspec) - -### `dedup` - -A dedup store will take the inputs and run a rolling hash -algorithm on them to slice the input into smaller parts then -run a sha256 algorithm on the slice and if the object doesn't -already exist, upload the slice to the `content_store` using -a new digest of just the slice. Once all parts exist, an -Action-Cache-like digest will be built and uploaded to the -`index_store` which will contain a reference to each -chunk/digest of the uploaded file. Downloading a request will -first grab the index from the `index_store`, and forward the -download content of each chunk as if it were one file. - -This store is exceptionally good when the following conditions -are met: -* Content is mostly the same (inserts, updates, deletes are ok) -* Content is not compressed or encrypted -* Uploading or downloading from `content_store` is the bottleneck. - -Note: This store pairs well when used with `CompressionSpec` as -the `content_store`, but never put `DedupSpec` as the backend of -`CompressionSpec` as it will negate all the gains. - -Note: When running `.has()` on this store, it will only check -to see if the entry exists in the `index_store` and not check -if the individual chunks exist in the `content_store`. - -**Example JSON5 config:** -```json5 -"dedup": { - "index_store": { - "memory": { - "eviction_policy": { - "max_bytes": "1GB", - } - } - }, - "content_store": { - "compression": { - "compression_algorithm": { - "lz4": {} - }, - "backend": { - "fast_slow": { - "fast": { - "memory": { - "eviction_policy": { - "max_bytes": "500MB", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-content", - "temp_path": "/tmp/nativelink/data/tmp_path-content", - "eviction_policy": { - "max_bytes": "2gb" - } - } - } - } - } - } - } -} -``` - -**Type:** [DedupSpec](#dedupspec) - -### `existence_cache` - -Existence store will wrap around another store and cache calls -to has so that subsequent `has_with_results` calls will be -faster. This is useful for cases when you have a store that -is slow to respond to has calls. -Note: This store should only be used on CAS stores. - -**Example JSON5 config:** -```json5 -"existence_cache": { - "backend": { - "memory": { - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - // Note this is the existence store policy, not the backend policy - "eviction_policy": { - "max_seconds": 100, - } -} -``` - -**Type:** [ExistenceCacheSpec](#existencecachespec) - -### `fast_slow` - -`FastSlow` store will first try to fetch the data from the `fast` -store and then if it does not exist try the `slow` store. -When the object does exist in the `slow` store, it will copy -the data to the `fast` store while returning the data. -This store should be thought of as a store that "buffers" -the data to the `fast` store. -On uploads it will mirror data to both `fast` and `slow` stores. - -WARNING: If you need data to always exist in the `slow` store -for something like remote execution, be careful because this -store will never check to see if the objects exist in the -`slow` store if it exists in the `fast` store (i.e., it assumes -that if an object exists in the `fast` store it will exist in -the `slow` store). - -***Example JSON5 config:*** -```json5 -"fast_slow": { - "fast": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - }, - "slow": { - "filesystem": { - "content_path": "/tmp/nativelink/data/content_path-index", - "temp_path": "/tmp/nativelink/data/tmp_path-index", - "eviction_policy": { - "max_bytes": "500mb", - } - } - } -} -``` - -**Type:** [FastSlowSpec](#fastslowspec) - -### `shard` - -Shards the data to multiple stores. This is useful for cases -when you want to distribute the load across multiple stores. -The digest hash is used to determine which store to send the -data to. - -**Example JSON5 config:** -```json5 -"shard": { - "stores": [ - { - "store": { - "memory": { - "eviction_policy": { - "max_bytes": "10mb" - }, - }, - }, - "weight": 1 - }] -} -``` - -**Type:** [ShardSpec](#shardspec) - -### `filesystem` - -Stores the data on the filesystem. This store is designed for -local persistent storage. Restarts of this program should restore -the previous state, meaning anything uploaded will be persistent -as long as the filesystem integrity holds. - -**Example JSON5 config:** -```json5 -"filesystem": { - "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", - "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", - "eviction_policy": { - "max_bytes": "10gb", - } -} -``` - -**Type:** [FilesystemSpec](#filesystemspec) - -### `ref_store` - -Store used to reference a store in the root store manager. -This is useful for cases when you want to share a store in different -nested stores. Example, you may want to share the same memory store -used for the action cache, but use a `FastSlowSpec` and have the fast -store also share the memory store for efficiency. - -**Example JSON5 config:** -```json5 -"ref_store": { - "name": "FS_CONTENT_STORE" -} -``` - -**Type:** [RefSpec](#refspec) - -### `size_partitioning` - -Uses the size field of the digest to separate which store to send the -data. This is useful for cases when you'd like to put small objects -in one store and large objects in another store. This should only be -used if the size field is the real size of the content, in other -words, don't use on AC (Action Cache) stores. Any store where you can -safely use `VerifySpec.verify_size = true`, this store should be safe -to use (i.e., CAS stores). - -**Example JSON5 config:** -```json5 -"size_partitioning": { - "size": "128mib", - "lower_store": { - "memory": { - "eviction_policy": { - "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" - } - } - }, - "upper_store": { - /// This store discards data larger than 128mib. - "noop": {} - } -} -``` - -**Type:** [SizePartitioningSpec](#sizepartitioningspec) - -### `grpc` - -This store will pass-through calls to another GRPC store. This store -is not designed to be used as a sub-store of another store, but it -does satisfy the interface and will likely work. - -One major GOTCHA is that some stores use a special function on this -store to get the size of the underlying object, which is only reliable -when this store is serving the a CAS store, not an AC store. If using -this store directly without being a child of any store there are no -side effects and is the most efficient way to use it. - -**Example JSON5 config:** -```json5 -"grpc": { - "instance_name": "main", - "endpoints": [ - {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} - ], - "connections_per_endpoint": "5", - "rpc_timeout_s": "5m", - "store_type": "ac", - // Static headers attached to every outgoing request to the upstream - // remote cache. Useful for fixed service-account credentials. - "headers": { - "authorization": "Bearer my-static-token" - }, - // Header names to copy from the inbound client request and forward to - // the upstream remote cache. Use this to pass through dynamic - // credentials such as a JWT sent by the build client. - "forward_headers": ["authorization", "x-custom-token"] -} -``` - -**Type:** [GrpcSpec](#grpcspec) - -### `redis_store` - -Stores data in any stores compatible with Redis APIs. - -Pairs well with `SizePartitioning` and/or `FastSlow` stores. -Ideal for accepting small object sizes as most Redis store -services have a max file upload of between 256Mb-512Mb. - -**Example JSON5 config:** -```json5 -"redis_store": { - "addresses": [ - "redis://127.0.0.1:6379/", - ], - "max_client_permits": 1000, -} -``` - -**Type:** [RedisSpec](#redisspec) - -### `noop` - -Noop store is a store that sends streams into the void and all data -retrieval will return 404 (`NotFound`). This can be useful for cases -where you may need to partition your data and part of your data needs -to be discarded. - -**Example JSON5 config:** -```json5 -"noop": {} -``` - -**Type:** [NoopSpec](#noopspec) - -### `experimental_mongo` - -Experimental `MongoDB` store implementation. - -This store uses `MongoDB` as a backend for storing data. It supports -both CAS (Content Addressable Storage) and scheduler data with -optional change streams for real-time updates. - -**Example JSON5 config:** -```json5 -"experimental_mongo": { - "connection_string": "mongodb://localhost:27017", - "database": "nativelink", - "cas_collection": "cas", - "key_prefix": "cas:", - "read_chunk_size": 65536, - "max_concurrent_uploads": 10, - "enable_change_streams": false, - "max_requests": "100" -} -``` - -**Type:** [ExperimentalMongoSpec](#experimentalmongospec) - ## EvictionPolicy Eviction policy always works on LRU (Least Recently Used). Any time an entry @@ -1645,7 +1064,7 @@ Configuration for an individual shard of the store. | Field | Type | Required | Default | Description | | --- | --- | --- | --- | --- | -| `store` | [StoreSpec](#storespec) | Yes | — | Store to shard the data to. | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | | `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | ## GrpcEndpoint diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.5.2.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.5.2.mdx new file mode 100644 index 000000000..e57c2537b --- /dev/null +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.5.2.mdx @@ -0,0 +1,1460 @@ +--- +title: Configuration reference +description: Every knob in the NativeLink JSON5 configuration — types, defaults, and links to source, autogenerated from the Rust config crate. +full: true +--- + +{/* AUTOGENERATED — do not edit by hand. + Source: nativelink-config @ v1.5.2 (6e63ef9a) + Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} + + + +This is the canonical NativeLink configuration reference for **v1.5.2**. +It is autogenerated from the Rust config crate +([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src)) via the `build-schema` binary, so +it can never drift from what the binary actually deserializes. + +## Top-level fields + +The root object (`CasConfig`) accepts the following fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stores` | array of [NamedStoreConfig](#namedstoreconfig) | Yes | List of stores available to use in this config. The keys can be used in other configs when needing to reference a store. | +| `workers` | array of [WorkerConfig](#workerconfig) | — | Worker configurations used to execute jobs. | +| `schedulers` | array of [NamedSchedulerConfig](#namedschedulerconfig) | — | List of schedulers available to use in this config. The keys can be used in other configs when needing to reference a scheduler. | +| `servers` | array of [ServerConfig](#serverconfig) | Yes | Servers to setup for this process. | +| `experimental_origin_events` | [OriginEventsSpec](#origineventsspec) | — | Experimental - Origin events configuration. This is the service that will collect and publish nativelink events to a store for processing by an external service. | +| `global` | [GlobalConfig](#globalconfig) | — | Any global configurations that apply to all modules live here. | + +## Configuration types + +Every type reachable from the root configuration, in reading order. + +## NamedStoreConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `cache_metrics` + +Cache metrics store wraps another store and emits low-cardinality +OpenTelemetry cache operation metrics for the wrapped store. + +This wrapper is opt-in. Stores that are not explicitly wrapped by +`cache_metrics` are constructed exactly as they are without this +wrapper and do not pay its hot-path timing or recording cost. + +**Example JSON5 config:** +```json5 +"cache_metrics": { + "cache_type": "cas", + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-cas", + "temp_path": "~/.cache/nativelink/tmp_path-cas" + } + } +} +``` + +**Type:** [CacheMetricsSpec](#cachemetricsspec) + +### `memory` + +Memory store will store all data in a hash map in memory. + +**Example JSON5 config:** +```json5 +"memory": { + "eviction_policy": { + "max_bytes": "10mb", + } +} +``` + +**Type:** [MemorySpec](#memoryspec) + +### `experimental_cloud_object_store` + +A generic blob store that will store files on the cloud +provider. This configuration will never delete files, so you are +responsible for purging old files in other ways. +It supports the following backends: + +1. **Amazon S3:** + S3 store will use Amazon's S3 service as a backend to store + the files. This configuration can be used to share files + across multiple instances. Uses system certificates for TLS + verification via `rustls-platform-verifier`. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "aws", + "region": "eu-north-1", + "bucket": "crossplane-bucket-af79aeca9", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +2. **Google Cloud Storage:** + GCS store uses Google's GCS service as a backend to store + the files. This configuration can be used to share files + across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "gcs", + "bucket": "test-bucket", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +3. **Azure Blob Store:** + Azure Blob store will use Microsoft's Azure Blob service as a + backend to store the files. This configuration can be used to + share files across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "azure", + "account_name": "cloudshell1393657559", + "container": "simple-test-container", + "key_prefix": "folder/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend + to store files. This store is specifically configured for ONTAP's S3 requirements + including custom TLS configuration, credentials management, and proper vserver + configuration. + + This store uses AWS environment variables for credentials: + - `AWS_ACCESS_KEY_ID` + - `AWS_SECRET_ACCESS_KEY` + - `AWS_DEFAULT_REGION` + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "ontap", + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "root_certificates": "/path/to/certs.pem", // Optional + "key_prefix": "test-prefix/", // Optional + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) + +### `ontap_s3_existence_cache` + +ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store +to optimize repeated existence checks. It maintains an in-memory cache of object +digests and periodically syncs this cache to disk for persistence. + +The cache helps reduce latency for repeated calls to check object existence, +while still ensuring eventual consistency with the underlying ONTAP S3 store. + +Example JSON5 config: +```json5 +"ontap_s3_existence_cache": { + "index_path": "/path/to/cache/index.json", + "sync_interval_seconds": 300, + "backend": { + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "key_prefix": "test-prefix/" + } +} +``` + +**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) + +### `verify` + +Verify store is used to apply verifications to an underlying +store implementation. It is strongly encouraged to validate +as much data as you can before accepting data from a client, +failing to do so may cause the data in the store to be +populated with invalid data causing all kinds of problems. + +The suggested configuration is to have the CAS validate the +hash and size and the AC validate nothing. + +**Example JSON5 config:** +```json5 +"verify": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb" + } + }, + }, + "verify_size": true, + "verify_hash": true +} +``` + +**Type:** [VerifySpec](#verifyspec) + +### `completeness_checking` + +Completeness checking store verifies if the +output files & folders exist in the CAS before forwarding +the request to the underlying store. +Note: This store should only be used on AC stores. + +**Example JSON5 config:** +```json5 +"completeness_checking": { + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-ac", + "temp_path": "~/.cache/nativelink/tmp_path-ac", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "cas_store": { + "ref_store": { + "name": "CAS_MAIN_STORE" + } + } +} +``` + +**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) + +### `compression` + +A compression store that will compress the data inbound and +outbound. There will be a non-trivial cost to compress and +decompress the data, but in many cases if the final store is +a store that requires network transport and/or storage space +is a concern it is often faster and more efficient to use this +store before those stores. + +**Example JSON5 config:** +```json5 +"compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-cas", + "temp_path": "/tmp/nativelink/data/tmp_path-cas", + "eviction_policy": { + "max_bytes": "2gb", + } + } + } +} +``` + +**Type:** [CompressionSpec](#compressionspec) + +### `dedup` + +A dedup store will take the inputs and run a rolling hash +algorithm on them to slice the input into smaller parts then +run a sha256 algorithm on the slice and if the object doesn't +already exist, upload the slice to the `content_store` using +a new digest of just the slice. Once all parts exist, an +Action-Cache-like digest will be built and uploaded to the +`index_store` which will contain a reference to each +chunk/digest of the uploaded file. Downloading a request will +first grab the index from the `index_store`, and forward the +download content of each chunk as if it were one file. + +This store is exceptionally good when the following conditions +are met: +* Content is mostly the same (inserts, updates, deletes are ok) +* Content is not compressed or encrypted +* Uploading or downloading from `content_store` is the bottleneck. + +Note: This store pairs well when used with `CompressionSpec` as +the `content_store`, but never put `DedupSpec` as the backend of +`CompressionSpec` as it will negate all the gains. + +Note: When running `.has()` on this store, it will only check +to see if the entry exists in the `index_store` and not check +if the individual chunks exist in the `content_store`. + +**Example JSON5 config:** +```json5 +"dedup": { + "index_store": { + "memory": { + "eviction_policy": { + "max_bytes": "1GB", + } + } + }, + "content_store": { + "compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "fast_slow": { + "fast": { + "memory": { + "eviction_policy": { + "max_bytes": "500MB", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-content", + "temp_path": "/tmp/nativelink/data/tmp_path-content", + "eviction_policy": { + "max_bytes": "2gb" + } + } + } + } + } + } + } +} +``` + +**Type:** [DedupSpec](#dedupspec) + +### `existence_cache` + +Existence store will wrap around another store and cache calls +to has so that subsequent `has_with_results` calls will be +faster. This is useful for cases when you have a store that +is slow to respond to has calls. +Note: This store should only be used on CAS stores. + +**Example JSON5 config:** +```json5 +"existence_cache": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + // Note this is the existence store policy, not the backend policy + "eviction_policy": { + "max_seconds": 100, + } +} +``` + +**Type:** [ExistenceCacheSpec](#existencecachespec) + +### `fast_slow` + +`FastSlow` store will first try to fetch the data from the `fast` +store and then if it does not exist try the `slow` store. +When the object does exist in the `slow` store, it will copy +the data to the `fast` store while returning the data. +This store should be thought of as a store that "buffers" +the data to the `fast` store. +On uploads it will mirror data to both `fast` and `slow` stores. + +WARNING: If you need data to always exist in the `slow` store +for something like remote execution, be careful because this +store will never check to see if the objects exist in the +`slow` store if it exists in the `fast` store (i.e., it assumes +that if an object exists in the `fast` store it will exist in +the `slow` store). + +***Example JSON5 config:*** +```json5 +"fast_slow": { + "fast": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + } +} +``` + +**Type:** [FastSlowSpec](#fastslowspec) + +### `shard` + +Shards the data to multiple stores. This is useful for cases +when you want to distribute the load across multiple stores. +The digest hash is used to determine which store to send the +data to. + +**Example JSON5 config:** +```json5 +"shard": { + "stores": [ + { + "store": { + "memory": { + "eviction_policy": { + "max_bytes": "10mb" + }, + }, + }, + "weight": 1 + }] +} +``` + +**Type:** [ShardSpec](#shardspec) + +### `filesystem` + +Stores the data on the filesystem. This store is designed for +local persistent storage. Restarts of this program should restore +the previous state, meaning anything uploaded will be persistent +as long as the filesystem integrity holds. + +**Example JSON5 config:** +```json5 +"filesystem": { + "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", + "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", + "eviction_policy": { + "max_bytes": "10gb", + } +} +``` + +**Type:** [FilesystemSpec](#filesystemspec) + +### `ref_store` + +Store used to reference a store in the root store manager. +This is useful for cases when you want to share a store in different +nested stores. Example, you may want to share the same memory store +used for the action cache, but use a `FastSlowSpec` and have the fast +store also share the memory store for efficiency. + +**Example JSON5 config:** +```json5 +"ref_store": { + "name": "FS_CONTENT_STORE" +} +``` + +**Type:** [RefSpec](#refspec) + +### `size_partitioning` + +Uses the size field of the digest to separate which store to send the +data. This is useful for cases when you'd like to put small objects +in one store and large objects in another store. This should only be +used if the size field is the real size of the content, in other +words, don't use on AC (Action Cache) stores. Any store where you can +safely use `VerifySpec.verify_size = true`, this store should be safe +to use (i.e., CAS stores). + +**Example JSON5 config:** +```json5 +"size_partitioning": { + "size": "128mib", + "lower_store": { + "memory": { + "eviction_policy": { + "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" + } + } + }, + "upper_store": { + /// This store discards data larger than 128mib. + "noop": {} + } +} +``` + +**Type:** [SizePartitioningSpec](#sizepartitioningspec) + +### `grpc` + +This store will pass-through calls to another GRPC store. This store +is not designed to be used as a sub-store of another store, but it +does satisfy the interface and will likely work. + +One major GOTCHA is that some stores use a special function on this +store to get the size of the underlying object, which is only reliable +when this store is serving the a CAS store, not an AC store. If using +this store directly without being a child of any store there are no +side effects and is the most efficient way to use it. + +**Example JSON5 config:** +```json5 +"grpc": { + "instance_name": "main", + "endpoints": [ + {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} + ], + "connections_per_endpoint": "5", + "rpc_timeout_s": "5m", + "store_type": "ac", + // Static headers attached to every outgoing request to the upstream + // remote cache. Useful for fixed service-account credentials. + "headers": { + "authorization": "Bearer my-static-token" + }, + // Header names to copy from the inbound client request and forward to + // the upstream remote cache. Use this to pass through dynamic + // credentials such as a JWT sent by the build client. + "forward_headers": ["authorization", "x-custom-token"] +} +``` + +**Type:** [GrpcSpec](#grpcspec) + +### `redis_store` + +Stores data in any stores compatible with Redis APIs. + +Pairs well with `SizePartitioning` and/or `FastSlow` stores. +Ideal for accepting small object sizes as most Redis store +services have a max file upload of between 256Mb-512Mb. + +**Example JSON5 config:** +```json5 +"redis_store": { + "addresses": [ + "redis://127.0.0.1:6379/", + ], + "max_client_permits": 1000, +} +``` + +**Type:** [RedisSpec](#redisspec) + +### `noop` + +Noop store is a store that sends streams into the void and all data +retrieval will return 404 (`NotFound`). This can be useful for cases +where you may need to partition your data and part of your data needs +to be discarded. + +**Example JSON5 config:** +```json5 +"noop": {} +``` + +**Type:** [NoopSpec](#noopspec) + +### `experimental_mongo` + +Experimental `MongoDB` store implementation. + +This store uses `MongoDB` as a backend for storing data. It supports +both CAS (Content Addressable Storage) and scheduler data with +optional change streams for real-time updates. + +**Example JSON5 config:** +```json5 +"experimental_mongo": { + "connection_string": "mongodb://localhost:27017", + "database": "nativelink", + "cas_collection": "cas", + "key_prefix": "cas:", + "read_chunk_size": 65536, + "max_concurrent_uploads": 10, + "enable_change_streams": false, + "max_requests": "100" +} +``` + +**Type:** [ExperimentalMongoSpec](#experimentalmongospec) + +## WorkerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `local` + +A worker type that executes jobs locally on this machine. + +**Type:** [LocalWorkerConfig](#localworkerconfig) + +## NamedSchedulerConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## ServerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {index of server in config} | Name of the server. This is used to help identify the service for telemetry and logs. | +| `listener` | [ListenerConfig](#listenerconfig) | Yes | — | Configuration | +| `services` | [ServicesConfig](#servicesconfig) | — | — | Services to attach to server. | +| `experimental_identity_header` | [IdentityHeaderSpec](#identityheaderspec) | — | {see `IdentityHeaderSpec`} | The config related to identifying the client. | + +## OriginEventsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `publisher` | [OriginEventsPublisherSpec](#origineventspublisherspec) | Yes | — | The publisher configuration for origin events. | +| `max_event_queue_size` | integer (uint) | — | 65536 (zero defaults to this) | The maximum number of events to queue before applying back pressure. IMPORTANT: Backpressure causes all clients to slow down significantly. Zero is default. | + +## GlobalConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_open_files` | integer (uint) | Yes | 24576 (= 24 * 1024) | Maximum number of open files that can be opened at one time. This value is not strictly enforced, it is a best effort. Some internal libraries open files or read metadata from a files which do not obey this limit, however the vast majority of cases will have this limit be honored. This value must be larger than `ulimit -n` to have any effect. Any network open file descriptors is not counted in this limit, but is counted in the kernel limit. It is a good idea to set a very large `ulimit -n`. Note: This value must be greater than 10. | +| `default_digest_hash_function` | [ConfigDigestHashFunction](#configdigesthashfunction) | — | `ConfigDigestHashFunction::sha256` | Default hash function to use while uploading blobs to the CAS when not set by client. | +| `default_digest_size_health_check` | integer (uint) | — | 1024*1024 (1MiB) | Default digest size to use for health check when running diagnostics checks. Health checks are expected to use this size for filling a buffer that is used for creation of digest. | + +## CacheMetricsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | + +## MemorySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## ExperimentalCloudObjectSpec + +See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for details + +## OntapS3ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_path` | string | Yes | — | | +| `sync_interval_seconds` | integer (uint32) | Yes | — | | +| `backend` | [ExperimentalOntapS3Spec](#experimentalontaps3spec) | Yes | — | | + +## VerifySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | +| `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | + +## CompletenessCheckingSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | + +## CompressionSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | + +## DedupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | +| `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | +| `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | +| `max_concurrent_fetch_per_get` | integer (uint32) | — | 10 | Due to implementation detail, we want to prefer to download the first chunks of the file so we can stream the content out and free up some of our buffers. This configuration will be used to restrict the number of concurrent chunk downloads at a time per `get()` request. | + +## ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## FastSlowSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | +| `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | + +## ShardSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `stores` | array of [ShardConfig](#shardconfig) | Yes | — | Stores to shard the data to. | + +## FilesystemSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service startup this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e., move without copy). All files in this folder will be deleted on every startup. | +| `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | +| `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | +| `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | + +## RefSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | Name of the store under the root "stores" config object. | + +## SizePartitioningSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `size` | integer (uint64) | Yes | — | Size to partition the data on. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | + +## GrpcSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Instance name for GRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | +| `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | `0` | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. Default 1. | +| `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | +| `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | +| `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | +| `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | + +## RedisSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `addresses` | array of string | Yes | — | The hostname or IP address of the Redis server. Ex: `["redis://username:password@redis-server-url:6380/99"]` 99 Represents database ID, 6380 represents the port. | +| `response_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `command_timeout_ms` The response timeout for the Redis connection in seconds. | +| `connection_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `connection_timeout_ms` | +| `experimental_pub_sub_channel` | string | — | (Empty String / No Channel) | An optional and experimental Redis channel to publish write events to. | +| `key_prefix` | string | — | (Empty String / No Prefix) | An optional prefix to prepend to all keys in this store. | +| `mode` | [RedisMode](#redismode) | — | standard, | Set the mode Redis is operating in. | +| `broadcast_channel_capacity` | integer (uint) | — | `0` | Deprecated as redis-rs doesn't use it | +| `command_timeout_ms` | integer (uint64) | — | 10000 (10 seconds) | The amount of time in milliseconds until the Redis store considers the command to be timed out. This will trigger a retry of the command and potentially a reconnection to the Redis server. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 (3 seconds) | The amount of time in milliseconds until the Redis store considers the connection to unresponsive. This will trigger a reconnection to the Redis server. | +| `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | +| `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | +| `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it is a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | +| `max_count_per_cursor` | integer (uint64) | — | 1500 | Maximum number of items returned per cursor for the search indexes May reduce thundering herd issues with worker provisioner at higher node counts, | + +## NoopSpec + +_No fields._ + +## ExperimentalMongoSpec + +Configuration for `ExperimentalMongoDB` store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `connection_string` | string | Yes | — | `ExperimentalMongoDB` connection string. Example: <mongodb://localhost:27017> or <mongodb+srv://cluster.mongodb.net> | +| `database` | string | — | "nativelink" | The database name to use. | +| `cas_collection` | string | — | "cas" | The collection name for CAS data. | +| `scheduler_collection` | string | — | "scheduler" | The collection name for scheduler data. | +| `key_prefix` | string | — | "" | Prefix to prepend to all keys stored in `MongoDB`. | +| `read_chunk_size` | integer (uint) | — | 65536 (64KB) | The maximum amount of data to read from `MongoDB` in a single chunk (in bytes). | +| `max_concurrent_uploads` | integer (uint) | — | 10 | Deprecated, unused Maximum number of concurrent uploads allowed. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 | Connection timeout in milliseconds. | +| `command_timeout_ms` | integer (uint64) | — | 10000 | Command timeout in milliseconds. | +| `enable_change_streams` | boolean | — | false | Enable `MongoDB` change streams for real-time updates. Required for scheduler subscriptions. | +| `write_concern_w` | string | — | — | Write concern 'w' parameter. Can be a number (e.g., 1) or string (e.g., "majority"). | +| `write_concern_j` | boolean | — | — | Write concern 'j' parameter (journal acknowledgment). | +| `write_concern_timeout_ms` | integer (uint32) | — | — | Write concern timeout in milliseconds. | +| `max_requests` | integer (uint) | — | Unlimited | Limits the number of requests at any one time | + +## LocalWorkerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e., "{name}{uuidv6}"). | +| `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | +| `max_action_timeout` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | +| `max_upload_timeout` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | +| `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | +| `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | +| `experimental_precondition_script` | string | — | — | An optional script to run before every action is processed on the worker. The value should be the full path to the script to execute and will pause all actions on the worker if it returns an exit code other than 0. If not set, then the worker will never pause and will continue to accept jobs according to the scheduler configuration. This is useful, for example, if the worker should not take any more actions until there is enough resource available on the machine to handle them. | +| `cas_fast_slow_store` | string | Yes | — | Underlying CAS store that the worker will use to download CAS artifacts. This store must be a `FastSlowStore`. The `fast` store must be a `FileSystemStore` because it will use hardlinks when building out the files instead of copying the files. The slow store must eventually resolve to the same store the scheduler/client uses to send job requests. | +| `upload_action_result` | [UploadActionResultConfig](#uploadactionresultconfig) | — | — | Configuration for uploading action results. | +| `work_directory` | string | Yes | — | The directory work jobs will be executed from. This directory will be fully managed by the worker service and will be purged on startup. This directory and the directory referenced in `local_filesystem_store_ref`'s `stores::FilesystemStore::content_path` must be on the same filesystem. Hardlinks will be used when placing files that are accessible to the jobs that are sourced from `local_filesystem_store_ref`'s `content_path`. | +| `platform_properties` | map of string to [WorkerProperty](#workerproperty) | Yes | — | Properties of this worker. This configuration will be sent to the scheduler and used to tell the scheduler to restrict what should be executed on this worker. | +| `additional_environment` | map of string to [EnvironmentSource](#environmentsource) | — | — | An optional mapping of environment names to set for the execution as well as those specified in the action itself. If set, will set each key as an environment variable before executing the job with the value of the environment variable being the value of the property of the action being executed of that name or the fixed value. | +| `directory_cache` | [DirectoryCacheConfig](#directorycacheconfig) | — | — | Optional directory cache configuration for improving performance by caching reconstructed input directories and using hardlinks instead of rebuilding them from CAS for every action. | +| `use_namespaces` | boolean | — | False | Whether to use namespaces to isolate the execution. This is only available on Linux. It is highly recommended as it avoids a number of issues with zombie processes and also provides additional hermeticity. If explicitly set to true and it is not supported the worker will exit with an error. | +| `use_mount_namespace` | boolean | — | False | Whether to use a mount namespace to isolate the worker root. This is only available on Linux and when `use_namespaces` is true. It is highly recommended provides additional hermeticity. If explicitly set to true and it is not supported or `use_namespaces` is not set to true the worker will exit with an error. | + +## SimpleSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `supported_platform_properties` | map of string to [PropertyType](#propertytype) | — | — | A list of supported platform properties mapped to how these properties are used when the scheduler looks for worker nodes capable of running the task. | +| `retain_completed_for_s` | integer (uint32) | — | 60 seconds | The amount of time to retain completed actions for in case a `WaitExecution` is called after the action has completed. | +| `client_action_timeout_s` | integer (uint64) | — | 60 seconds | Mark operations as completed with error if no client has updated them within this duration. | +| `worker_timeout_s` | integer (uint64) | — | 5 seconds | Remove workers from pool once the worker has not responded in this amount of time in seconds. | +| `max_action_executing_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) an action can stay in Executing state without any worker update before being timed out and re-queued. This applies regardless of worker keepalive status, catching cases where a worker is alive (sending keepalives) but stuck on a specific action. Set to 0 to disable (relies only on `worker_timeout_s`). | +| `max_job_retries` | integer (uint) | — | 3 | If a job returns an internal error or times out this many times when attempting to run on a worker the scheduler will return the last error to the client. Jobs will be retried and this configuration is to help prevent one rogue job from infinitely retrying and taking up a lot of resources when the task itself is the one causing the server to go into a bad state. | +| `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | +| `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | +| `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | + +## SchedulerGrpcSpec + +A scheduler that forwards requests to an upstream scheduler. This +is useful to use when doing some kind of local action cache or CAS away from +the main cluster of workers. In general, it's more efficient to point the +build at the main scheduler directly though. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | [GrpcEndpoint](#grpcendpoint) | Yes | — | The upstream scheduler to forward requests to. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | unlimited | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | + +## CacheLookupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | Yes | — | The reference to the action cache store used to return cached actions from rather than running them again. To prevent unintended issues, this store should probably be a `CompletenessCheckingSpec`. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use if cache lookup fails. | + +## PropertyModifierSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `modifications` | array of [PropertyModification](#propertymodification) | Yes | — | A list of modifications to perform to incoming actions for the nested scheduler. These are performed in order and blindly, so removing a property that doesn't exist is fine and overwriting an existing property is also fine. If adding properties that do not exist in the nested scheduler is not supported and will likely cause unexpected behaviour. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after modifying the properties. | + +## HistoricalResourceSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `hints_file` | string | Yes | — | JSON file containing historical resource hints keyed by Bazel `RequestMetadata` `target_id` and/or `action_mnemonic`. | +| `refresh_interval_s` | integer (uint64) | — | 30 seconds | Reload interval for `hints_file`. Set to 0 to load once. | +| `cpu_property_name` | string | — | `cpu_count` | Platform property name used for CPU minimum values. | +| `memory_property_name` | string | — | `memory_kb` | Platform property name used for memory minimum values, expressed in KiB. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after applying resource hints. | + +## ListenerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `http` + +Listener for HTTP/HTTPS/HTTP2 sockets. + +**Type:** [HttpListener](#httplistener) + +## ServicesConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | +| `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel GRPC service. | +| `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | +| `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | +| `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | +| `push` | array of [PushServiceConfig](#pushserviceconfig) | — | — | | +| `worker_api` | [WorkerApiConfig](#workerapiconfig) | — | — | This is the service used for workers to connect and communicate through. NOTE: This service should be served on a different, non-public port. In other words, `worker_api` configuration should not have any other services that are served on the same port. Doing so is a security risk, as workers have a different permission set than a client that makes the remote execution/cache requests. | +| `experimental_bep` | [BepConfig](#bepconfig) | — | — | Experimental - Build Event Protocol (BEP) configuration. This is the service that will consume build events from the client and publish them to a store for processing by an external service. | +| `admin` | [AdminConfig](#adminconfig) | — | — | This is the service for any administrative tasks. It provides a REST API endpoint for administrative purposes. | +| `health` | [HealthConfig](#healthconfig) | — | — | This is the service for health status check. | + +## IdentityHeaderSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `header_name` | string | — | "x-identity" | The name of the header to look for the identity in. | +| `required` | boolean | — | `false` | If the header is required to be set or fail the request. | + +## OriginEventsPublisherSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish nativelink events to. The store name referenced in the `stores` map in the main config. | + +## ConfigDigestHashFunction + +| Value | Description | +| --- | --- | +| `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | +| `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | + +## EvictionPolicy + +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | + +## Retry + +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, +} +``` +will result in: + +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | + +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this is not set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | + +## ExperimentalOntapS3Spec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | + +## CompressionAlgorithm + +Plus exactly one of the following variants (the key selects the variant): + +### `lz4` + +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. + +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) + +**Type:** [Lz4Config](#lz4config) + +## StoreDirection + +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | + +## ShardConfig + +Configuration for an individual shard of the store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | + +## GrpcEndpoint + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. grpc://example.com:443 or grpcs://example.com:443). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | + +## StoreType + +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | + +## RedisMode + +| Value | Description | +| --- | --- | +| `"cluster"` | Use Redis Cluster. | +| `"sentinel"` | Use Redis Sentinel. | +| `"standard"` | Use a standalone Redis server. | + +## EndpointConfig + +Generic config for an endpoint and associated configs. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `uri` | string | Yes | — | URI of the endpoint. | +| `timeout` | number (float) | — | 5 seconds | Timeout in seconds that a request should take. | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint. | + +## UploadActionResultConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | — | {No uploading is done} | Underlying AC store that the worker will use to publish execution results into. Objects placed in this store should be reachable from the scheduler/client-cas after they have finished updating. | +| `upload_ac_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `SuccessOnly` | In which situations should the results be published to the `ac_store`, if set to `SuccessOnly` then only results with an exit code of 0 will be uploaded, if set to Everything all completed results will be uploaded. | +| `historical_results_store` | string | — | {CAS store of parent} | Store to upload historical results to. This should be a CAS store if set. | +| `upload_historical_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `FailuresOnly` | In which situations should the results be published to the historical CAS. The historical CAS is where failures are published. These messages conform to the CAS key-value lookup format and are always a `HistoricalExecuteResponse` serialized message. | +| `success_message_template` | string | — | "" (no message) | Template to use for the `ExecuteResponse.message` property. This message is attached to the response before it is sent to the client. The following special variables are supported:; `digest_function`: Digest function used to calculate the action digest: `action_digest_hash`: Action digest hash: `action_digest_size`: Action digest size: `historical_results_hash`: `HistoricalExecuteResponse` digest hash: `historical_results_size`: `HistoricalExecuteResponse` digest size. | +| `failure_message_template` | string | — | "" (no message) | Same as `success_message_template` but for failure case. | + +## WorkerProperty + +Plus exactly one of the following variants (the key selects the variant): + +### `values` + +List of static values. +Note: Generally there should only ever be 1 value, but if the platform +property key is `PropertyType::Priority` it may have more than one value. + +**Type:** array of string + +### `query_cmd` + +A dynamic configuration. The string will be executed as a command +(not shell) and will be split by "\n" (new line character). + +**Type:** string + +## EnvironmentSource + +One of: + +- `property`: string — The name of the platform property in the action to get the value from. +- `value`: string — The raw value to set. +- `"from_environment"` — Take the value from the local environment corresponding to the name key +- `"timeout_millis"` — The max amount of time in milliseconds the command is allowed to run (requested by the client). +- `"side_channel_file"` — A special file path will be provided that can be used to communicate with the parent process about out-of-band information. This file will be read after the command has finished executing. Based on the contents of the file, the behavior of the result may be modified. +- `"action_directory"` — A "root" directory for the action. This directory can be used to store temporary files that are not needed after the action has completed. This directory will be purged after the action has completed. + +## DirectoryCacheConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | +| `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | +| `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | + +## PropertyType + +When the scheduler matches tasks to workers that are capable of running +the task, this value will be used to determine how the property is treated. + +One of: + +- string +- `"minimum"` — Requires the platform property to be a u64 and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that has less than this value. +- `"exact"` — Requires the platform property to be a string and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that does not have this property set to the value with exact string match. +- `"priority"` — Does not restrict on this value and instead will be passed to the worker as an informational piece. In the future this will be used by the scheduler and worker to cause the scheduler to prefer certain workers over others, but not restrict them based on these values. + +## WorkerAllocationStrategy + +When a worker is being searched for to run a job, this will be used +on how to choose which worker should run the job when multiple +workers are able to run the task. + +| Value | Description | +| --- | --- | +| `"least_recently_used"` | Prefer workers that have been least recently used to run a job. | +| `"most_recently_used"` | Prefer workers that have been most recently used to run a job. | + +## ExperimentalSimpleSchedulerBackend + +One of: + +- `"memory"` — Use an in-memory store for the scheduler. +- `redis`: [ExperimentalRedisSchedulerBackend](#experimentalredisschedulerbackend) — Use a Redis store for the scheduler. + +## SchedulerSpec + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## PropertyModification + +Plus exactly one of the following variants (the key selects the variant): + +### `add` + +Add a property to the action properties. + +**Type:** [PlatformPropertyAddition](#platformpropertyaddition) + +### `remove` + +Remove a named property from the action. + +**Type:** string + +### `replace` + +If a property is found, then replace it with another one. + +**Type:** [PlatformPropertyReplacement](#platformpropertyreplacement) + +## HttpListener + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `socket_address` | string | Yes | — | Address to listen on. Example: `127.0.0.1:8080` or `:8080` to listen to all IPs. | +| `freebind` | boolean | — | false | Allow binding `socket_address` before it is assigned locally. | +| `compression` | [HttpCompressionConfig](#httpcompressionconfig) | — | — | Data transport compression configuration to use for this service. | +| `advanced_http` | [HttpServerConfig](#httpserverconfig) | — | — | Advanced HTTP server configuration. | +| `max_decoding_message_size` | integer (uint) | — | 4 MiB | Maximum number of bytes to decode on each grpc stream chunk. | +| `tls` | [TlsConfig](#tlsconfig) | — | — | TLS configuration for this server. If not set, the server will not use TLS. | + +## CasServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## ActionCacheServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `ac_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## CapabilitiesServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | + +## ExecutionServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. This value must be a CAS store reference. | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## ByteStreamServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | Name of the store in the "stores" configuration. | +| `max_bytes_per_stream` | integer (uint) | — | 64KiB | Max number of bytes to send on each grpc stream chunk. According to [https://github.com/grpc/grpc.github.io/issues/371](https://github.com/grpc/grpc.github.io/issues/371) 16KiB - 64KiB is optimal. | +| `persist_stream_on_disconnect_timeout` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | + +## FetchServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `fetch_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## PushServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `push_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## WorkerApiConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## BepConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish build events to. The store name referenced in the `stores` map in the main config. | + +## AdminConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/admin" | Path to register the admin API. If path is "/admin", and your domain is "example.com", you can reach the endpoint with: [http://example.com/admin](http://example.com/admin). | + +## HealthConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/status" | Path to register the health status check. If path is "/status", and your domain is "example.com", you can reach the endpoint with: [http://example.com/status](http://example.com/status). | +| `timeout_seconds` | integer (uint64) | — | 5s | Timeout on health checks. | + +## ErrorCode + +The possible error codes that might occur on an upstream request. + +| Value | Description | +| --- | --- | +| `"Cancelled"` | | +| `"Unknown"` | | +| `"InvalidArgument"` | | +| `"DeadlineExceeded"` | | +| `"NotFound"` | | +| `"AlreadyExists"` | | +| `"PermissionDenied"` | | +| `"ResourceExhausted"` | | +| `"FailedPrecondition"` | | +| `"Aborted"` | | +| `"OutOfRange"` | | +| `"Unimplemented"` | | +| `"Internal"` | | +| `"Unavailable"` | | +| `"DataLoss"` | | +| `"Unauthenticated"` | | + +## Lz4Config + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `block_size` | integer (uint32) | — | 65536 (64k) | Size of the blocks to compress. Higher values require more ram, but might yield slightly better compression ratios. | +| `max_decode_block_size` | integer (uint32) | — | value in `block_size` | Maximum size allowed to attempt to deserialize data into. This is needed because the `block_size` is embedded into the data so if there was a bad actor, they could upload an extremely large `block_size`'ed entry and we'd allocate a large amount of memory when retrieving the data. To prevent this from happening, we allow you to specify the maximum that we'll attempt to deserialize. | + +## ClientTlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ca_file` | string | — | — | Path to the certificate authority to use to validate the remote. | +| `cert_file` | string | — | — | Path to the certificate file for client authentication. | +| `key_file` | string | — | — | Path to the private key file for client authentication. | +| `use_native_roots` | boolean | — | false | If set the client will use the native roots for TLS connections. | + +## UploadCacheResultsStrategy + +| Value | Description | +| --- | --- | +| `"success_only"` | Only upload action results with an exit code of 0. | +| `"never"` | Don't upload any action results. | +| `"everything"` | Upload all action results that complete. | +| `"failures_only"` | Only upload action results that fail. | + +## ExperimentalRedisSchedulerBackend + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `redis_store` | string | Yes | — | A reference to the Redis store to use for the scheduler. Note: This MUST resolve to a `RedisSpec`. | + +## PlatformPropertyAddition + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to add. | +| `value` | string | Yes | — | The value to assign to the property. | + +## PlatformPropertyReplacement + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to replace. | +| `value` | string | — | — | The value to match against, if unset then any instance matches. | +| `new_name` | string | Yes | — | The new name of the property. | +| `new_value` | string | — | — | The value to assign to the property, if unset will remain the same. | + +## HttpCompressionConfig + +Note: Compressing data in the cloud rarely has a benefit, since most +cloud providers have very high bandwidth backplanes. However, for +clients not inside the data center, it might be a good idea to +compress data to and from the cloud. This will however come at a high +CPU and performance cost. If you are making remote execution share the +same CAS/AC servers as client's remote cache, you can create multiple +services with different compression settings that are served on +different ports. Then configure the non-cloud clients to use one port +and cloud-clients to use another. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `send_compression_algorithm` | [HttpCompressionAlgorithm](#httpcompressionalgorithm) | — | `HttpCompressionAlgorithm::None` | The compression algorithm that the server will use when sending responses to clients. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | +| `accepted_compression_algorithms` | array of [HttpCompressionAlgorithm](#httpcompressionalgorithm) | Yes | {no supported compression} | The compression algorithm that the server will accept from clients. The server will broadcast the supported compression algorithms to clients and the client will choose which compression algorithm to use. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | + +## HttpServerConfig + +Advanced HTTP configuration. These generally should not be set. +For documentation on these settings, see the hyper documentation: +See: [hyper HTTP server docs](https://docs.rs/hyper/latest/hyper/server/conn/struct.Http.html) + +Note: All of these default to the default values from hyper unless otherwise +specified. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `http2_keep_alive_interval` | integer (uint32) | — | — | Interval to send keep-alive pings via HTTP2. Note: This is in seconds. | +| `experimental_http2_max_pending_accept_reset_streams` | integer (uint32) | — | — | | +| `experimental_http2_initial_stream_window_size` | integer (uint32) | — | — | | +| `experimental_http2_initial_connection_window_size` | integer (uint32) | — | — | | +| `experimental_http2_adaptive_window` | boolean | — | — | | +| `experimental_http2_max_frame_size` | integer (uint32) | — | — | | +| `experimental_http2_max_concurrent_streams` | integer (uint32) | — | — | | +| `experimental_http2_keep_alive_timeout` | integer (uint32) | — | — | Note: This is in seconds. | +| `experimental_http2_max_send_buf_size` | integer (uint32) | — | — | | +| `experimental_http2_enable_connect_protocol` | boolean | — | — | | +| `experimental_http2_max_header_list_size` | integer (uint32) | — | — | | + +## TlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cert_file` | string | Yes | — | Path to the certificate file. | +| `key_file` | string | Yes | — | Path to the private key file. | +| `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | +| `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | + +## CapabilitiesRemoteExecutionConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | Scheduler used to configure the capabilities of remote execution. | + +## HttpCompressionAlgorithm + +| Value | Description | +| --- | --- | +| `"none"` | No compression. | +| `"gzip"` | Zlib compression. | + +## Reading the source + +If anything here disagrees with the binary, the source wins: + +- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src/stores.rs) +- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src/cas_server.rs) +- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.5.2/nativelink-config/src/schedulers.rs) diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.6.0.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.0.mdx new file mode 100644 index 000000000..74644a0e1 --- /dev/null +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.0.mdx @@ -0,0 +1,1511 @@ +--- +title: Configuration reference +description: Every knob in the NativeLink JSON5 configuration — types, defaults, and links to source, autogenerated from the Rust config crate. +full: true +--- + +{/* AUTOGENERATED — do not edit by hand. + Source: nativelink-config @ v1.6.0 (05c5fac5) + Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} + + + +This is the canonical NativeLink configuration reference for **v1.6.0**. +It is autogenerated from the Rust config crate +([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.6.0/nativelink-config/src)) via the `build-schema` binary, so +it can never drift from what the binary actually deserializes. + +## Top-level fields + +The root object (`CasConfig`) accepts the following fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stores` | array of [NamedStoreConfig](#namedstoreconfig) | Yes | List of stores available to use in this config. The keys can be used in other configs when needing to reference a store. | +| `workers` | array of [WorkerConfig](#workerconfig) | — | Worker configurations used to execute jobs. | +| `schedulers` | array of [NamedSchedulerConfig](#namedschedulerconfig) | — | List of schedulers available to use in this config. The keys can be used in other configs when needing to reference a scheduler. | +| `servers` | array of [ServerConfig](#serverconfig) | Yes | Servers to setup for this process. | +| `experimental_origin_events` | [OriginEventsSpec](#origineventsspec) | — | Experimental - Origin events configuration. This is the service that will collect and publish nativelink events to a store for processing by an external service. | +| `global` | [GlobalConfig](#globalconfig) | — | Any global configurations that apply to all modules live here. | + +## Configuration types + +Every type reachable from the root configuration, in reading order. + +## NamedStoreConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `cache_metrics` + +Cache metrics store wraps another store and emits low-cardinality +OpenTelemetry cache operation metrics for the wrapped store. + +This wrapper is opt-in. Stores that are not explicitly wrapped by +`cache_metrics` are constructed exactly as they are without this +wrapper and do not pay its hot-path timing or recording cost. + +**Example JSON5 config:** +```json5 +"cache_metrics": { + "cache_type": "cas", + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-cas", + "temp_path": "~/.cache/nativelink/tmp_path-cas" + } + } +} +``` + +**Type:** [CacheMetricsSpec](#cachemetricsspec) + +### `memory` + +Memory store will store all data in a hash map in memory. + +**Example JSON5 config:** +```json5 +"memory": { + "eviction_policy": { + "max_bytes": "10mb", + } +} +``` + +**Type:** [MemorySpec](#memoryspec) + +### `experimental_cloud_object_store` + +A generic blob store that will store files on the cloud +provider. This configuration will never delete files, so you are +responsible for purging old files in other ways. +It supports the following backends: + +1. **Amazon S3:** + S3 store will use Amazon's S3 service as a backend to store + the files. This configuration can be used to share files + across multiple instances. Uses system certificates for TLS + verification via `rustls-platform-verifier`. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "aws", + "region": "eu-north-1", + "bucket": "crossplane-bucket-af79aeca9", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +2. **Google Cloud Storage:** + GCS store uses Google's GCS service as a backend to store + the files. This configuration can be used to share files + across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "gcs", + "bucket": "test-bucket", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +3. **Azure Blob Store:** + Azure Blob store will use Microsoft's Azure Blob service as a + backend to store the files. This configuration can be used to + share files across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "azure", + "account_name": "cloudshell1393657559", + "container": "simple-test-container", + "key_prefix": "folder/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend + to store files. This store is specifically configured for ONTAP's S3 requirements + including custom TLS configuration, credentials management, and proper vserver + configuration. + + This store uses AWS environment variables for credentials: + - `AWS_ACCESS_KEY_ID` + - `AWS_SECRET_ACCESS_KEY` + - `AWS_DEFAULT_REGION` + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "ontap", + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "root_certificates": "/path/to/certs.pem", // Optional + "key_prefix": "test-prefix/", // Optional + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +5. **Cloudflare R2:** + R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + S3 API, so this is a thin wrapper that derives the account-scoped + endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + Storage API. The path-style endpoint is derived from your Object + Storage `namespace` and `region` as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + Authenticate with a Customer Secret Key (Access Key/Secret Key pair + created under User Settings -> Customer secret keys in the OCI + console); the secret cannot be retrieved after generation, so read + it from an env var via shellexpand. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + ``` + +**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) + +### `ontap_s3_existence_cache` + +ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store +to optimize repeated existence checks. It maintains an in-memory cache of object +digests and periodically syncs this cache to disk for persistence. + +The cache helps reduce latency for repeated calls to check object existence, +while still ensuring eventual consistency with the underlying ONTAP S3 store. + +Example JSON5 config: +```json5 +"ontap_s3_existence_cache": { + "index_path": "/path/to/cache/index.json", + "sync_interval_seconds": 300, + "backend": { + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "key_prefix": "test-prefix/" + } +} +``` + +**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) + +### `verify` + +Verify store is used to apply verifications to an underlying +store implementation. It is strongly encouraged to validate +as much data as you can before accepting data from a client, +failing to do so may cause the data in the store to be +populated with invalid data causing all kinds of problems. + +The suggested configuration is to have the CAS validate the +hash and size and the AC validate nothing. + +**Example JSON5 config:** +```json5 +"verify": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb" + } + }, + }, + "verify_size": true, + "verify_hash": true +} +``` + +**Type:** [VerifySpec](#verifyspec) + +### `completeness_checking` + +Completeness checking store verifies if the +output files & folders exist in the CAS before forwarding +the request to the underlying store. +Note: This store should only be used on AC stores. + +**Example JSON5 config:** +```json5 +"completeness_checking": { + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-ac", + "temp_path": "~/.cache/nativelink/tmp_path-ac", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "cas_store": { + "ref_store": { + "name": "CAS_MAIN_STORE" + } + } +} +``` + +**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) + +### `compression` + +A compression store that will compress the data inbound and +outbound. There will be a non-trivial cost to compress and +decompress the data, but in many cases if the final store is +a store that requires network transport and/or storage space +is a concern it is often faster and more efficient to use this +store before those stores. + +**Example JSON5 config:** +```json5 +"compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-cas", + "temp_path": "/tmp/nativelink/data/tmp_path-cas", + "eviction_policy": { + "max_bytes": "2gb", + } + } + } +} +``` + +**Type:** [CompressionSpec](#compressionspec) + +### `dedup` + +A dedup store will take the inputs and run a rolling hash +algorithm on them to slice the input into smaller parts then +run a sha256 algorithm on the slice and if the object doesn't +already exist, upload the slice to the `content_store` using +a new digest of just the slice. Once all parts exist, an +Action-Cache-like digest will be built and uploaded to the +`index_store` which will contain a reference to each +chunk/digest of the uploaded file. Downloading a request will +first grab the index from the `index_store`, and forward the +download content of each chunk as if it were one file. + +This store is exceptionally good when the following conditions +are met: +* Content is mostly the same (inserts, updates, deletes are ok) +* Content is not compressed or encrypted +* Uploading or downloading from `content_store` is the bottleneck. + +Note: This store pairs well when used with `CompressionSpec` as +the `content_store`, but never put `DedupSpec` as the backend of +`CompressionSpec` as it will negate all the gains. + +Note: When running `.has()` on this store, it will only check +to see if the entry exists in the `index_store` and not check +if the individual chunks exist in the `content_store`. + +**Example JSON5 config:** +```json5 +"dedup": { + "index_store": { + "memory": { + "eviction_policy": { + "max_bytes": "1GB", + } + } + }, + "content_store": { + "compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "fast_slow": { + "fast": { + "memory": { + "eviction_policy": { + "max_bytes": "500MB", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-content", + "temp_path": "/tmp/nativelink/data/tmp_path-content", + "eviction_policy": { + "max_bytes": "2gb" + } + } + } + } + } + } + } +} +``` + +**Type:** [DedupSpec](#dedupspec) + +### `existence_cache` + +Existence store will wrap around another store and cache calls +to has so that subsequent `has_with_results` calls will be +faster. This is useful for cases when you have a store that +is slow to respond to has calls. +Note: This store should only be used on CAS stores. + +**Example JSON5 config:** +```json5 +"existence_cache": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + // Note this is the existence store policy, not the backend policy + "eviction_policy": { + "max_seconds": 100, + } +} +``` + +**Type:** [ExistenceCacheSpec](#existencecachespec) + +### `fast_slow` + +`FastSlow` store will first try to fetch the data from the `fast` +store and then if it does not exist try the `slow` store. +When the object does exist in the `slow` store, it will copy +the data to the `fast` store while returning the data. +This store should be thought of as a store that "buffers" +the data to the `fast` store. +On uploads it will mirror data to both `fast` and `slow` stores. + +WARNING: If you need data to always exist in the `slow` store +for something like remote execution, be careful because this +store will never check to see if the objects exist in the +`slow` store if it exists in the `fast` store (i.e., it assumes +that if an object exists in the `fast` store it will exist in +the `slow` store). + +***Example JSON5 config:*** +```json5 +"fast_slow": { + "fast": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + } +} +``` + +**Type:** [FastSlowSpec](#fastslowspec) + +### `shard` + +Shards the data to multiple stores. This is useful for cases +when you want to distribute the load across multiple stores. +The digest hash is used to determine which store to send the +data to. + +**Example JSON5 config:** +```json5 +"shard": { + "stores": [ + { + "store": { + "memory": { + "eviction_policy": { + "max_bytes": "10mb" + }, + }, + }, + "weight": 1 + }] +} +``` + +**Type:** [ShardSpec](#shardspec) + +### `filesystem` + +Stores the data on the filesystem. This store is designed for +local persistent storage. Restarts of this program should restore +the previous state, meaning anything uploaded will be persistent +as long as the filesystem integrity holds. + +**Example JSON5 config:** +```json5 +"filesystem": { + "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", + "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", + "eviction_policy": { + "max_bytes": "10gb", + } +} +``` + +**Type:** [FilesystemSpec](#filesystemspec) + +### `ref_store` + +Store used to reference a store in the root store manager. +This is useful for cases when you want to share a store in different +nested stores. Example, you may want to share the same memory store +used for the action cache, but use a `FastSlowSpec` and have the fast +store also share the memory store for efficiency. + +**Example JSON5 config:** +```json5 +"ref_store": { + "name": "FS_CONTENT_STORE" +} +``` + +**Type:** [RefSpec](#refspec) + +### `size_partitioning` + +Uses the size field of the digest to separate which store to send the +data. This is useful for cases when you'd like to put small objects +in one store and large objects in another store. This should only be +used if the size field is the real size of the content, in other +words, don't use on AC (Action Cache) stores. Any store where you can +safely use `VerifySpec.verify_size = true`, this store should be safe +to use (i.e., CAS stores). + +**Example JSON5 config:** +```json5 +"size_partitioning": { + "size": "128mib", + "lower_store": { + "memory": { + "eviction_policy": { + "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" + } + } + }, + "upper_store": { + /// This store discards data larger than 128mib. + "noop": {} + } +} +``` + +**Type:** [SizePartitioningSpec](#sizepartitioningspec) + +### `grpc` + +This store will pass-through calls to another GRPC store. This store +is not designed to be used as a sub-store of another store, but it +does satisfy the interface and will likely work. + +One major GOTCHA is that some stores use a special function on this +store to get the size of the underlying object, which is only reliable +when this store is serving the a CAS store, not an AC store. If using +this store directly without being a child of any store there are no +side effects and is the most efficient way to use it. + +**Example JSON5 config:** +```json5 +"grpc": { + "instance_name": "main", + "endpoints": [ + {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} + ], + "connections_per_endpoint": "5", + "rpc_timeout_s": "5m", + "store_type": "ac", + // Static headers attached to every outgoing request to the upstream + // remote cache. Useful for fixed service-account credentials. + "headers": { + "authorization": "Bearer my-static-token" + }, + // Header names to copy from the inbound client request and forward to + // the upstream remote cache. Use this to pass through dynamic + // credentials such as a JWT sent by the build client. + "forward_headers": ["authorization", "x-custom-token"] +} +``` + +**Type:** [GrpcSpec](#grpcspec) + +### `redis_store` + +Stores data in any stores compatible with Redis APIs. + +Pairs well with `SizePartitioning` and/or `FastSlow` stores. +Ideal for accepting small object sizes as most Redis store +services have a max file upload of between 256Mb-512Mb. + +**Example JSON5 config:** +```json5 +"redis_store": { + "addresses": [ + "redis://127.0.0.1:6379/", + ], + "max_client_permits": 1000, +} +``` + +**Type:** [RedisSpec](#redisspec) + +### `noop` + +Noop store is a store that sends streams into the void and all data +retrieval will return 404 (`NotFound`). This can be useful for cases +where you may need to partition your data and part of your data needs +to be discarded. + +**Example JSON5 config:** +```json5 +"noop": {} +``` + +**Type:** [NoopSpec](#noopspec) + +### `experimental_mongo` + +Experimental `MongoDB` store implementation. + +This store uses `MongoDB` as a backend for storing data. It supports +both CAS (Content Addressable Storage) and scheduler data with +optional change streams for real-time updates. + +**Example JSON5 config:** +```json5 +"experimental_mongo": { + "connection_string": "mongodb://localhost:27017", + "database": "nativelink", + "cas_collection": "cas", + "key_prefix": "cas:", + "read_chunk_size": 65536, + "max_concurrent_uploads": 10, + "enable_change_streams": false, + "max_requests": "100" +} +``` + +**Type:** [ExperimentalMongoSpec](#experimentalmongospec) + +## WorkerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `local` + +A worker type that executes jobs locally on this machine. + +**Type:** [LocalWorkerConfig](#localworkerconfig) + +## NamedSchedulerConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## ServerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {index of server in config} | Name of the server. This is used to help identify the service for telemetry and logs. | +| `listener` | [ListenerConfig](#listenerconfig) | Yes | — | Configuration | +| `services` | [ServicesConfig](#servicesconfig) | — | — | Services to attach to server. | +| `experimental_identity_header` | [IdentityHeaderSpec](#identityheaderspec) | — | {see `IdentityHeaderSpec`} | The config related to identifying the client. | + +## OriginEventsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `publisher` | [OriginEventsPublisherSpec](#origineventspublisherspec) | Yes | — | The publisher configuration for origin events. | +| `max_event_queue_size` | integer (uint) | — | 65536 (zero defaults to this) | The maximum number of events to queue before applying back pressure. IMPORTANT: Backpressure causes all clients to slow down significantly. Zero is default. | + +## GlobalConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_open_files` | integer (uint) | Yes | 24576 (= 24 * 1024) | Maximum number of open files that can be opened at one time. This value is not strictly enforced, it is a best effort. Some internal libraries open files or read metadata from a files which do not obey this limit, however the vast majority of cases will have this limit be honored. This value must be larger than `ulimit -n` to have any effect. Any network open file descriptors is not counted in this limit, but is counted in the kernel limit. It is a good idea to set a very large `ulimit -n`. Note: This value must be greater than 10. | +| `default_digest_hash_function` | [ConfigDigestHashFunction](#configdigesthashfunction) | — | `ConfigDigestHashFunction::sha256` | Default hash function to use while uploading blobs to the CAS when not set by client. | +| `default_digest_size_health_check` | integer (uint) | — | 1024*1024 (1MiB) | Default digest size to use for health check when running diagnostics checks. Health checks are expected to use this size for filling a buffer that is used for creation of digest. | + +## CacheMetricsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | + +## MemorySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## ExperimentalCloudObjectSpec + +See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for details + +## OntapS3ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_path` | string | Yes | — | | +| `sync_interval_seconds` | integer (uint32) | Yes | — | | +| `backend` | [ExperimentalOntapS3Spec](#experimentalontaps3spec) | Yes | — | | + +## VerifySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | +| `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | + +## CompletenessCheckingSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | + +## CompressionSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | + +## DedupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | +| `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | +| `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | +| `max_concurrent_fetch_per_get` | integer (uint32) | — | 10 | Due to implementation detail, we want to prefer to download the first chunks of the file so we can stream the content out and free up some of our buffers. This configuration will be used to restrict the number of concurrent chunk downloads at a time per `get()` request. | + +## ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## FastSlowSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | +| `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | + +## ShardSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `stores` | array of [ShardConfig](#shardconfig) | Yes | — | Stores to shard the data to. | + +## FilesystemSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service startup this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e., move without copy). All files in this folder will be deleted on every startup. | +| `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | +| `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | +| `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | + +## RefSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | Name of the store under the root "stores" config object. | + +## SizePartitioningSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `size` | integer (uint64) | Yes | — | Size to partition the data on. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | + +## GrpcSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Instance name for GRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | +| `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | `0` | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. Default 1. | +| `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | +| `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | +| `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | +| `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | + +## RedisSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `addresses` | array of string | Yes | — | The hostname or IP address of the Redis server. Ex: `["redis://username:password@redis-server-url:6380/99"]` 99 Represents database ID, 6380 represents the port. | +| `response_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `command_timeout_ms` The response timeout for the Redis connection in seconds. | +| `connection_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `connection_timeout_ms` | +| `experimental_pub_sub_channel` | string | — | (Empty String / No Channel) | An optional and experimental Redis channel to publish write events to. | +| `key_prefix` | string | — | (Empty String / No Prefix) | An optional prefix to prepend to all keys in this store. | +| `mode` | [RedisMode](#redismode) | — | standard, | Set the mode Redis is operating in. | +| `broadcast_channel_capacity` | integer (uint) | — | `0` | Deprecated as redis-rs doesn't use it | +| `command_timeout_ms` | integer (uint64) | — | 10000 (10 seconds) | The amount of time in milliseconds until the Redis store considers the command to be timed out. This will trigger a retry of the command and potentially a reconnection to the Redis server. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 (3 seconds) | The amount of time in milliseconds until the Redis store considers the connection to unresponsive. This will trigger a reconnection to the Redis server. | +| `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | +| `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | +| `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it is a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | +| `max_count_per_cursor` | integer (uint64) | — | 1500 | Maximum number of items returned per cursor for the search indexes May reduce thundering herd issues with worker provisioner at higher node counts, | + +## NoopSpec + +_No fields._ + +## ExperimentalMongoSpec + +Configuration for `ExperimentalMongoDB` store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `connection_string` | string | Yes | — | `ExperimentalMongoDB` connection string. Example: <mongodb://localhost:27017> or <mongodb+srv://cluster.mongodb.net> | +| `database` | string | — | "nativelink" | The database name to use. | +| `cas_collection` | string | — | "cas" | The collection name for CAS data. | +| `scheduler_collection` | string | — | "scheduler" | The collection name for scheduler data. | +| `key_prefix` | string | — | "" | Prefix to prepend to all keys stored in `MongoDB`. | +| `read_chunk_size` | integer (uint) | — | 65536 (64KB) | The maximum amount of data to read from `MongoDB` in a single chunk (in bytes). | +| `max_concurrent_uploads` | integer (uint) | — | 10 | Deprecated, unused Maximum number of concurrent uploads allowed. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 | Connection timeout in milliseconds. | +| `command_timeout_ms` | integer (uint64) | — | 10000 | Command timeout in milliseconds. | +| `enable_change_streams` | boolean | — | false | Enable `MongoDB` change streams for real-time updates. Required for scheduler subscriptions. | +| `write_concern_w` | string | — | — | Write concern 'w' parameter. Can be a number (e.g., 1) or string (e.g., "majority"). | +| `write_concern_j` | boolean | — | — | Write concern 'j' parameter (journal acknowledgment). | +| `write_concern_timeout_ms` | integer (uint32) | — | — | Write concern timeout in milliseconds. | +| `max_requests` | integer (uint) | — | Unlimited | Limits the number of requests at any one time | + +## LocalWorkerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e., "{name}{uuidv6}"). | +| `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | +| `max_action_timeout_s` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | +| `max_upload_timeout_s` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. Value in seconds. | +| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. Value in milliseconds. | +| `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | +| `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | +| `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | +| `experimental_precondition_script` | string | — | — | An optional script to run before every action is processed on the worker. The value should be the full path to the script to execute and will pause all actions on the worker if it returns an exit code other than 0. If not set, then the worker will never pause and will continue to accept jobs according to the scheduler configuration. This is useful, for example, if the worker should not take any more actions until there is enough resource available on the machine to handle them. | +| `cas_fast_slow_store` | string | Yes | — | Underlying CAS store that the worker will use to download CAS artifacts. This store must be a `FastSlowStore`. The `fast` store must be a `FileSystemStore` because it will use hardlinks when building out the files instead of copying the files. The slow store must eventually resolve to the same store the scheduler/client uses to send job requests. | +| `upload_action_result` | [UploadActionResultConfig](#uploadactionresultconfig) | — | — | Configuration for uploading action results. | +| `work_directory` | string | Yes | — | The directory work jobs will be executed from. This directory will be fully managed by the worker service and will be purged on startup. This directory and the directory referenced in `local_filesystem_store_ref`'s `stores::FilesystemStore::content_path` must be on the same filesystem. Hardlinks will be used when placing files that are accessible to the jobs that are sourced from `local_filesystem_store_ref`'s `content_path`. | +| `platform_properties` | map of string to [WorkerProperty](#workerproperty) | Yes | — | Properties of this worker. This configuration will be sent to the scheduler and used to tell the scheduler to restrict what should be executed on this worker. | +| `additional_environment` | map of string to [EnvironmentSource](#environmentsource) | — | — | An optional mapping of environment names to set for the execution as well as those specified in the action itself. If set, will set each key as an environment variable before executing the job with the value of the environment variable being the value of the property of the action being executed of that name or the fixed value. | +| `directory_cache` | [DirectoryCacheConfig](#directorycacheconfig) | — | — | Optional directory cache configuration for improving performance by caching reconstructed input directories and using hardlinks instead of rebuilding them from CAS for every action. | +| `use_namespaces` | boolean | — | False | Whether to use namespaces to isolate the execution. This is only available on Linux. It is highly recommended as it avoids a number of issues with zombie processes and also provides additional hermeticity. If explicitly set to true and it is not supported the worker will exit with an error. | +| `use_mount_namespace` | boolean | — | False | Whether to use a mount namespace to isolate the worker root. This is only available on Linux and when `use_namespaces` is true. It is highly recommended provides additional hermeticity. If explicitly set to true and it is not supported or `use_namespaces` is not set to true the worker will exit with an error. | + +## SimpleSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `supported_platform_properties` | map of string to [PropertyType](#propertytype) | — | — | A list of supported platform properties mapped to how these properties are used when the scheduler looks for worker nodes capable of running the task. | +| `retain_completed_for_s` | integer (uint32) | — | 60 seconds | The amount of time to retain completed actions for in case a `WaitExecution` is called after the action has completed. | +| `client_action_timeout_s` | integer (uint64) | — | 60 seconds | Mark operations as completed with error if no client has updated them within this duration. | +| `worker_timeout_s` | integer (uint64) | — | 5 seconds | Remove workers from pool once the worker has not responded in this amount of time in seconds. | +| `max_action_executing_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) an action can stay in Executing state without any worker update before being timed out and re-queued. This applies regardless of worker keepalive status, catching cases where a worker is alive (sending keepalives) but stuck on a specific action. Set to 0 to disable (relies only on `worker_timeout_s`). | +| `max_job_retries` | integer (uint) | — | 3 | If a job returns an internal error or times out this many times when attempting to run on a worker the scheduler will return the last error to the client. Jobs will be retried and this configuration is to help prevent one rogue job from infinitely retrying and taking up a lot of resources when the task itself is the one causing the server to go into a bad state. | +| `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | +| `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | +| `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | + +## SchedulerGrpcSpec + +A scheduler that forwards requests to an upstream scheduler. This +is useful to use when doing some kind of local action cache or CAS away from +the main cluster of workers. In general, it's more efficient to point the +build at the main scheduler directly though. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | [GrpcEndpoint](#grpcendpoint) | Yes | — | The upstream scheduler to forward requests to. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | unlimited | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | + +## CacheLookupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | Yes | — | The reference to the action cache store used to return cached actions from rather than running them again. To prevent unintended issues, this store should probably be a `CompletenessCheckingSpec`. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use if cache lookup fails. | + +## PropertyModifierSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `modifications` | array of [PropertyModification](#propertymodification) | Yes | — | A list of modifications to perform to incoming actions for the nested scheduler. These are performed in order and blindly, so removing a property that doesn't exist is fine and overwriting an existing property is also fine. If adding properties that do not exist in the nested scheduler is not supported and will likely cause unexpected behaviour. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after modifying the properties. | + +## HistoricalResourceSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `hints_file` | string | Yes | — | JSON file containing historical resource hints keyed by Bazel `RequestMetadata` `target_id` and/or `action_mnemonic`. | +| `refresh_interval_s` | integer (uint64) | — | 30 seconds | Reload interval for `hints_file`. Set to 0 to load once. | +| `cpu_property_name` | string | — | `cpu_count` | Platform property name used for CPU minimum values. | +| `memory_property_name` | string | — | `memory_kb` | Platform property name used for memory minimum values, expressed in KiB. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after applying resource hints. | + +## ListenerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `http` + +Listener for HTTP/HTTPS/HTTP2 sockets. + +**Type:** [HttpListener](#httplistener) + +## ServicesConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | +| `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel GRPC service. | +| `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | +| `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | +| `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | +| `push` | array of [PushServiceConfig](#pushserviceconfig) | — | — | | +| `worker_api` | [WorkerApiConfig](#workerapiconfig) | — | — | This is the service used for workers to connect and communicate through. NOTE: This service should be served on a different, non-public port. In other words, `worker_api` configuration should not have any other services that are served on the same port. Doing so is a security risk, as workers have a different permission set than a client that makes the remote execution/cache requests. | +| `experimental_bep` | [BepConfig](#bepconfig) | — | — | Experimental - Build Event Protocol (BEP) configuration. This is the service that will consume build events from the client and publish them to a store for processing by an external service. | +| `admin` | [AdminConfig](#adminconfig) | — | — | This is the service for any administrative tasks. It provides a REST API endpoint for administrative purposes. | +| `health` | [HealthConfig](#healthconfig) | — | — | This is the service for health status check. | + +## IdentityHeaderSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `header_name` | string | — | "x-identity" | The name of the header to look for the identity in. | +| `required` | boolean | — | `false` | If the header is required to be set or fail the request. | + +## OriginEventsPublisherSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish nativelink events to. The store name referenced in the `stores` map in the main config. | + +## ConfigDigestHashFunction + +| Value | Description | +| --- | --- | +| `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | +| `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | + +## EvictionPolicy + +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | + +## Retry + +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, +} +``` +will result in: + +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | + +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this is not set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | + +## ExperimentalOntapS3Spec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | + +## CompressionAlgorithm + +Plus exactly one of the following variants (the key selects the variant): + +### `lz4` + +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. + +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) + +**Type:** [Lz4Config](#lz4config) + +## StoreDirection + +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | + +## ShardConfig + +Configuration for an individual shard of the store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | + +## GrpcEndpoint + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. grpc://example.com:443 or grpcs://example.com:443). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | + +## StoreType + +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | + +## RedisMode + +| Value | Description | +| --- | --- | +| `"cluster"` | Use Redis Cluster. | +| `"sentinel"` | Use Redis Sentinel. | +| `"standard"` | Use a standalone Redis server. | + +## EndpointConfig + +Generic config for an endpoint and associated configs. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `uri` | string | Yes | — | URI of the endpoint. | +| `timeout` | number (float) | — | 5 seconds | Timeout in seconds that a request should take. | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint. | + +## UploadActionResultConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | — | {No uploading is done} | Underlying AC store that the worker will use to publish execution results into. Objects placed in this store should be reachable from the scheduler/client-cas after they have finished updating. | +| `upload_ac_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `SuccessOnly` | In which situations should the results be published to the `ac_store`, if set to `SuccessOnly` then only results with an exit code of 0 will be uploaded, if set to Everything all completed results will be uploaded. | +| `historical_results_store` | string | — | {CAS store of parent} | Store to upload historical results to. This should be a CAS store if set. | +| `upload_historical_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `FailuresOnly` | In which situations should the results be published to the historical CAS. The historical CAS is where failures are published. These messages conform to the CAS key-value lookup format and are always a `HistoricalExecuteResponse` serialized message. | +| `success_message_template` | string | — | "" (no message) | Template to use for the `ExecuteResponse.message` property. This message is attached to the response before it is sent to the client. The following special variables are supported:; `digest_function`: Digest function used to calculate the action digest: `action_digest_hash`: Action digest hash: `action_digest_size`: Action digest size: `historical_results_hash`: `HistoricalExecuteResponse` digest hash: `historical_results_size`: `HistoricalExecuteResponse` digest size. | +| `failure_message_template` | string | — | "" (no message) | Same as `success_message_template` but for failure case. | + +## WorkerProperty + +Plus exactly one of the following variants (the key selects the variant): + +### `values` + +List of static values. +Note: Generally there should only ever be 1 value, but if the platform +property key is `PropertyType::Priority` it may have more than one value. + +**Type:** array of string + +### `query_cmd` + +A dynamic configuration. The string will be executed as a command +(not shell) and will be split by "\n" (new line character). + +**Type:** string + +## EnvironmentSource + +One of: + +- `property`: string — The name of the platform property in the action to get the value from. +- `value`: string — The raw value to set. +- `"from_environment"` — Take the value from the local environment corresponding to the name key +- `"timeout_millis"` — The max amount of time in milliseconds the command is allowed to run (requested by the client). +- `"side_channel_file"` — A special file path will be provided that can be used to communicate with the parent process about out-of-band information. This file will be read after the command has finished executing. Based on the contents of the file, the behavior of the result may be modified. +- `"action_directory"` — A "root" directory for the action. This directory can be used to store temporary files that are not needed after the action has completed. This directory will be purged after the action has completed. + +## DirectoryCacheConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | +| `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | +| `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | + +## PropertyType + +When the scheduler matches tasks to workers that are capable of running +the task, this value will be used to determine how the property is treated. + +One of: + +- string +- `"minimum"` — Requires the platform property to be a u64 and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that has less than this value. +- `"exact"` — Requires the platform property to be a string and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that does not have this property set to the value with exact string match. +- `"priority"` — Does not restrict on this value and instead will be passed to the worker as an informational piece. In the future this will be used by the scheduler and worker to cause the scheduler to prefer certain workers over others, but not restrict them based on these values. + +## WorkerAllocationStrategy + +When a worker is being searched for to run a job, this will be used +on how to choose which worker should run the job when multiple +workers are able to run the task. + +| Value | Description | +| --- | --- | +| `"least_recently_used"` | Prefer workers that have been least recently used to run a job. | +| `"most_recently_used"` | Prefer workers that have been most recently used to run a job. | + +## ExperimentalSimpleSchedulerBackend + +One of: + +- `"memory"` — Use an in-memory store for the scheduler. +- `redis`: [ExperimentalRedisSchedulerBackend](#experimentalredisschedulerbackend) — Use a Redis store for the scheduler. + +## SchedulerSpec + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## PropertyModification + +Plus exactly one of the following variants (the key selects the variant): + +### `add` + +Add a property to the action properties. + +**Type:** [PlatformPropertyAddition](#platformpropertyaddition) + +### `remove` + +Remove a named property from the action. + +**Type:** string + +### `replace` + +If a property is found, then replace it with another one. + +**Type:** [PlatformPropertyReplacement](#platformpropertyreplacement) + +## HttpListener + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `socket_address` | string | Yes | — | Address to listen on. Example: `127.0.0.1:8080` or `:8080` to listen to all IPs. | +| `freebind` | boolean | — | false | Allow binding `socket_address` before it is assigned locally. | +| `compression` | [HttpCompressionConfig](#httpcompressionconfig) | — | — | Data transport compression configuration to use for this service. | +| `advanced_http` | [HttpServerConfig](#httpserverconfig) | — | — | Advanced HTTP server configuration. | +| `max_decoding_message_size` | integer (uint) | — | 4 MiB | Maximum number of bytes to decode on each grpc stream chunk. | +| `tls` | [TlsConfig](#tlsconfig) | — | — | TLS configuration for this server. If not set, the server will not use TLS. | + +## CasServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## ActionCacheServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `ac_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## CapabilitiesServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | + +## ExecutionServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. This value must be a CAS store reference. | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## ByteStreamServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | Name of the store in the "stores" configuration. | +| `max_bytes_per_stream` | integer (uint) | — | 64KiB | Max number of bytes to send on each grpc stream chunk. According to [https://github.com/grpc/grpc.github.io/issues/371](https://github.com/grpc/grpc.github.io/issues/371) 16KiB - 64KiB is optimal. | +| `persist_stream_on_disconnect_timeout_s` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | + +## FetchServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `fetch_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## PushServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `push_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## WorkerApiConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## BepConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish build events to. The store name referenced in the `stores` map in the main config. | + +## AdminConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/admin" | Path to register the admin API. If path is "/admin", and your domain is "example.com", you can reach the endpoint with: [http://example.com/admin](http://example.com/admin). | + +## HealthConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/status" | Path to register the health status check. If path is "/status", and your domain is "example.com", you can reach the endpoint with: [http://example.com/status](http://example.com/status). | +| `timeout_seconds` | integer (uint64) | — | 5s | Timeout on health checks. | + +## ErrorCode + +The possible error codes that might occur on an upstream request. + +| Value | Description | +| --- | --- | +| `"Cancelled"` | | +| `"Unknown"` | | +| `"InvalidArgument"` | | +| `"DeadlineExceeded"` | | +| `"NotFound"` | | +| `"AlreadyExists"` | | +| `"PermissionDenied"` | | +| `"ResourceExhausted"` | | +| `"FailedPrecondition"` | | +| `"Aborted"` | | +| `"OutOfRange"` | | +| `"Unimplemented"` | | +| `"Internal"` | | +| `"Unavailable"` | | +| `"DataLoss"` | | +| `"Unauthenticated"` | | + +## Lz4Config + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `block_size` | integer (uint32) | — | 65536 (64k) | Size of the blocks to compress. Higher values require more ram, but might yield slightly better compression ratios. | +| `max_decode_block_size` | integer (uint32) | — | value in `block_size` | Maximum size allowed to attempt to deserialize data into. This is needed because the `block_size` is embedded into the data so if there was a bad actor, they could upload an extremely large `block_size`'ed entry and we'd allocate a large amount of memory when retrieving the data. To prevent this from happening, we allow you to specify the maximum that we'll attempt to deserialize. | + +## ClientTlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ca_file` | string | — | — | Path to the certificate authority to use to validate the remote. | +| `cert_file` | string | — | — | Path to the certificate file for client authentication. | +| `key_file` | string | — | — | Path to the private key file for client authentication. | +| `use_native_roots` | boolean | — | false | If set the client will use the native roots for TLS connections. | + +## UploadCacheResultsStrategy + +| Value | Description | +| --- | --- | +| `"success_only"` | Only upload action results with an exit code of 0. | +| `"never"` | Don't upload any action results. | +| `"everything"` | Upload all action results that complete. | +| `"failures_only"` | Only upload action results that fail. | + +## ExperimentalRedisSchedulerBackend + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `redis_store` | string | Yes | — | A reference to the Redis store to use for the scheduler. Note: This MUST resolve to a `RedisSpec`. | + +## PlatformPropertyAddition + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to add. | +| `value` | string | Yes | — | The value to assign to the property. | + +## PlatformPropertyReplacement + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to replace. | +| `value` | string | — | — | The value to match against, if unset then any instance matches. | +| `new_name` | string | Yes | — | The new name of the property. | +| `new_value` | string | — | — | The value to assign to the property, if unset will remain the same. | + +## HttpCompressionConfig + +Note: Compressing data in the cloud rarely has a benefit, since most +cloud providers have very high bandwidth backplanes. However, for +clients not inside the data center, it might be a good idea to +compress data to and from the cloud. This will however come at a high +CPU and performance cost. If you are making remote execution share the +same CAS/AC servers as client's remote cache, you can create multiple +services with different compression settings that are served on +different ports. Then configure the non-cloud clients to use one port +and cloud-clients to use another. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `send_compression_algorithm` | [HttpCompressionAlgorithm](#httpcompressionalgorithm) | — | `HttpCompressionAlgorithm::None` | The compression algorithm that the server will use when sending responses to clients. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | +| `accepted_compression_algorithms` | array of [HttpCompressionAlgorithm](#httpcompressionalgorithm) | Yes | {no supported compression} | The compression algorithm that the server will accept from clients. The server will broadcast the supported compression algorithms to clients and the client will choose which compression algorithm to use. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | + +## HttpServerConfig + +Advanced HTTP configuration. These generally should not be set. +For documentation on these settings, see the hyper documentation: +See: [hyper HTTP server docs](https://docs.rs/hyper/latest/hyper/server/conn/struct.Http.html) + +Note: All of these default to the default values from hyper unless otherwise +specified. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `http2_keep_alive_interval` | integer (uint32) | — | — | Interval to send keep-alive pings via HTTP2. Note: This is in seconds. | +| `experimental_http2_max_pending_accept_reset_streams` | integer (uint32) | — | — | | +| `experimental_http2_initial_stream_window_size` | integer (uint32) | — | — | | +| `experimental_http2_initial_connection_window_size` | integer (uint32) | — | — | | +| `experimental_http2_adaptive_window` | boolean | — | — | | +| `experimental_http2_max_frame_size` | integer (uint32) | — | — | | +| `experimental_http2_max_concurrent_streams` | integer (uint32) | — | — | | +| `experimental_http2_keep_alive_timeout_s` | integer (uint32) | — | — | | +| `experimental_http2_max_send_buf_size` | integer (uint32) | — | — | | +| `experimental_http2_enable_connect_protocol` | boolean | — | — | | +| `experimental_http2_max_header_list_size` | integer (uint32) | — | — | | + +## TlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cert_file` | string | Yes | — | Path to the certificate file. | +| `key_file` | string | Yes | — | Path to the private key file. | +| `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | +| `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | + +## CapabilitiesRemoteExecutionConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | Scheduler used to configure the capabilities of remote execution. | + +## HttpCompressionAlgorithm + +| Value | Description | +| --- | --- | +| `"none"` | No compression. | +| `"gzip"` | Zlib compression. | + +## Reading the source + +If anything here disagrees with the binary, the source wins: + +- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.0/nativelink-config/src/stores.rs) +- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.0/nativelink-config/src/cas_server.rs) +- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.0/nativelink-config/src/schedulers.rs) diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.6.1.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.1.mdx new file mode 100644 index 000000000..e6c7307c2 --- /dev/null +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.1.mdx @@ -0,0 +1,1521 @@ +--- +title: Configuration reference +description: Every knob in the NativeLink JSON5 configuration — types, defaults, and links to source, autogenerated from the Rust config crate. +full: true +--- + +{/* AUTOGENERATED — do not edit by hand. + Source: nativelink-config @ v1.6.1 (23e960dc) + Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} + + + +This is the canonical NativeLink configuration reference for **v1.6.1**. +It is autogenerated from the Rust config crate +([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.6.1/nativelink-config/src)) via the `build-schema` binary, so +it can never drift from what the binary actually deserializes. + +## Top-level fields + +The root object (`CasConfig`) accepts the following fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stores` | array of [NamedStoreConfig](#namedstoreconfig) | Yes | List of stores available to use in this config. The keys can be used in other configs when needing to reference a store. | +| `workers` | array of [WorkerConfig](#workerconfig) | — | Worker configurations used to execute jobs. | +| `schedulers` | array of [NamedSchedulerConfig](#namedschedulerconfig) | — | List of schedulers available to use in this config. The keys can be used in other configs when needing to reference a scheduler. | +| `servers` | array of [ServerConfig](#serverconfig) | Yes | Servers to setup for this process. | +| `experimental_origin_events` | [OriginEventsSpec](#origineventsspec) | — | Experimental - Origin events configuration. This is the service that will collect and publish nativelink events to a store for processing by an external service. | +| `global` | [GlobalConfig](#globalconfig) | — | Any global configurations that apply to all modules live here. | + +## Configuration types + +Every type reachable from the root configuration, in reading order. + +## NamedStoreConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `cache_metrics` + +Cache metrics store wraps another store and emits low-cardinality +OpenTelemetry cache operation metrics for the wrapped store. + +This wrapper is opt-in. Stores that are not explicitly wrapped by +`cache_metrics` are constructed exactly as they are without this +wrapper and do not pay its hot-path timing or recording cost. + +**Example JSON5 config:** +```json5 +"cache_metrics": { + "cache_type": "cas", + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-cas", + "temp_path": "~/.cache/nativelink/tmp_path-cas" + } + } +} +``` + +**Type:** [CacheMetricsSpec](#cachemetricsspec) + +### `memory` + +Memory store will store all data in a hash map in memory. + +**Example JSON5 config:** +```json5 +"memory": { + "eviction_policy": { + "max_bytes": "10mb", + } +} +``` + +**Type:** [MemorySpec](#memoryspec) + +### `experimental_cloud_object_store` + +A generic blob store that will store files on the cloud +provider. This configuration will never delete files, so you are +responsible for purging old files in other ways. +It supports the following backends: + +1. **Amazon S3:** + S3 store will use Amazon's S3 service as a backend to store + the files. This configuration can be used to share files + across multiple instances. Uses system certificates for TLS + verification via `rustls-platform-verifier`. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "aws", + "region": "eu-north-1", + "bucket": "crossplane-bucket-af79aeca9", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +2. **Google Cloud Storage:** + GCS store uses Google's GCS service as a backend to store + the files. This configuration can be used to share files + across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "gcs", + "bucket": "test-bucket", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +3. **Azure Blob Store:** + Azure Blob store will use Microsoft's Azure Blob service as a + backend to store the files. This configuration can be used to + share files across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "azure", + "account_name": "cloudshell1393657559", + "container": "simple-test-container", + "key_prefix": "folder/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend + to store files. This store is specifically configured for ONTAP's S3 requirements + including custom TLS configuration, credentials management, and proper vserver + configuration. + + This store uses AWS environment variables for credentials: + - `AWS_ACCESS_KEY_ID` + - `AWS_SECRET_ACCESS_KEY` + - `AWS_DEFAULT_REGION` + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "ontap", + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "root_certificates": "/path/to/certs.pem", // Optional + "key_prefix": "test-prefix/", // Optional + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +5. **Cloudflare R2:** + R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + S3 API, so this is a thin wrapper that derives the account-scoped + endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + Storage API. The path-style endpoint is derived from your Object + Storage `namespace` and `region` as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + Authenticate with a Customer Secret Key (Access Key/Secret Key pair + created under User Settings -> Customer secret keys in the OCI + console); the secret cannot be retrieved after generation, so read + it from an env var via shellexpand. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + ``` + +**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) + +### `ontap_s3_existence_cache` + +ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store +to optimize repeated existence checks. It maintains an in-memory cache of object +digests and periodically syncs this cache to disk for persistence. + +The cache helps reduce latency for repeated calls to check object existence, +while still ensuring eventual consistency with the underlying ONTAP S3 store. + +Example JSON5 config: +```json5 +"ontap_s3_existence_cache": { + "index_path": "/path/to/cache/index.json", + "sync_interval_seconds": 300, + "backend": { + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "key_prefix": "test-prefix/" + } +} +``` + +**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) + +### `verify` + +Verify store is used to apply verifications to an underlying +store implementation. It is strongly encouraged to validate +as much data as you can before accepting data from a client, +failing to do so may cause the data in the store to be +populated with invalid data causing all kinds of problems. + +The suggested configuration is to have the CAS validate the +hash and size and the AC validate nothing. + +**Example JSON5 config:** +```json5 +"verify": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb" + } + }, + }, + "verify_size": true, + "verify_hash": true +} +``` + +**Type:** [VerifySpec](#verifyspec) + +### `completeness_checking` + +Completeness checking store verifies if the +output files & folders exist in the CAS before forwarding +the request to the underlying store. +Note: This store should only be used on AC stores. + +**Example JSON5 config:** +```json5 +"completeness_checking": { + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-ac", + "temp_path": "~/.cache/nativelink/tmp_path-ac", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "cas_store": { + "ref_store": { + "name": "CAS_MAIN_STORE" + } + } +} +``` + +**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) + +### `compression` + +A compression store that will compress the data inbound and +outbound. There will be a non-trivial cost to compress and +decompress the data, but in many cases if the final store is +a store that requires network transport and/or storage space +is a concern it is often faster and more efficient to use this +store before those stores. + +**Example JSON5 config:** +```json5 +"compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-cas", + "temp_path": "/tmp/nativelink/data/tmp_path-cas", + "eviction_policy": { + "max_bytes": "2gb", + } + } + } +} +``` + +**Type:** [CompressionSpec](#compressionspec) + +### `dedup` + +A dedup store will take the inputs and run a rolling hash +algorithm on them to slice the input into smaller parts then +run a sha256 algorithm on the slice and if the object doesn't +already exist, upload the slice to the `content_store` using +a new digest of just the slice. Once all parts exist, an +Action-Cache-like digest will be built and uploaded to the +`index_store` which will contain a reference to each +chunk/digest of the uploaded file. Downloading a request will +first grab the index from the `index_store`, and forward the +download content of each chunk as if it were one file. + +This store is exceptionally good when the following conditions +are met: +* Content is mostly the same (inserts, updates, deletes are ok) +* Content is not compressed or encrypted +* Uploading or downloading from `content_store` is the bottleneck. + +Note: This store pairs well when used with `CompressionSpec` as +the `content_store`, but never put `DedupSpec` as the backend of +`CompressionSpec` as it will negate all the gains. + +Note: When running `.has()` on this store, it will only check +to see if the entry exists in the `index_store` and not check +if the individual chunks exist in the `content_store`. + +**Example JSON5 config:** +```json5 +"dedup": { + "index_store": { + "memory": { + "eviction_policy": { + "max_bytes": "1GB", + } + } + }, + "content_store": { + "compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "fast_slow": { + "fast": { + "memory": { + "eviction_policy": { + "max_bytes": "500MB", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-content", + "temp_path": "/tmp/nativelink/data/tmp_path-content", + "eviction_policy": { + "max_bytes": "2gb" + } + } + } + } + } + } + } +} +``` + +**Type:** [DedupSpec](#dedupspec) + +### `existence_cache` + +Existence store will wrap around another store and cache calls +to has so that subsequent `has_with_results` calls will be +faster. This is useful for cases when you have a store that +is slow to respond to has calls. +Note: This store should only be used on CAS stores. + +**Example JSON5 config:** +```json5 +"existence_cache": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + // Note this is the existence store policy, not the backend policy + "eviction_policy": { + "max_seconds": 100, + } +} +``` + +**Type:** [ExistenceCacheSpec](#existencecachespec) + +### `fast_slow` + +`FastSlow` store will first try to fetch the data from the `fast` +store and then if it does not exist try the `slow` store. +When the object does exist in the `slow` store, it will copy +the data to the `fast` store while returning the data. +This store should be thought of as a store that "buffers" +the data to the `fast` store. +On uploads it will mirror data to both `fast` and `slow` stores. + +WARNING: If you need data to always exist in the `slow` store +for something like remote execution, be careful because this +store will never check to see if the objects exist in the +`slow` store if it exists in the `fast` store (i.e., it assumes +that if an object exists in the `fast` store it will exist in +the `slow` store). + +***Example JSON5 config:*** +```json5 +"fast_slow": { + "fast": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + } +} +``` + +**Type:** [FastSlowSpec](#fastslowspec) + +### `shard` + +Shards the data to multiple stores. This is useful for cases +when you want to distribute the load across multiple stores. +The digest hash is used to determine which store to send the +data to. + +**Example JSON5 config:** +```json5 +"shard": { + "stores": [ + { + "store": { + "memory": { + "eviction_policy": { + "max_bytes": "10mb" + }, + }, + }, + "weight": 1 + }] +} +``` + +**Type:** [ShardSpec](#shardspec) + +### `filesystem` + +Stores the data on the filesystem. This store is designed for +local persistent storage. Restarts of this program should restore +the previous state, meaning anything uploaded will be persistent +as long as the filesystem integrity holds. + +**Example JSON5 config:** +```json5 +"filesystem": { + "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", + "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", + "eviction_policy": { + "max_bytes": "10gb", + } +} +``` + +**Type:** [FilesystemSpec](#filesystemspec) + +### `ref_store` + +Store used to reference a store in the root store manager. +This is useful for cases when you want to share a store in different +nested stores. Example, you may want to share the same memory store +used for the action cache, but use a `FastSlowSpec` and have the fast +store also share the memory store for efficiency. + +**Example JSON5 config:** +```json5 +"ref_store": { + "name": "FS_CONTENT_STORE" +} +``` + +**Type:** [RefSpec](#refspec) + +### `size_partitioning` + +Uses the size field of the digest to separate which store to send the +data. This is useful for cases when you'd like to put small objects +in one store and large objects in another store. This should only be +used if the size field is the real size of the content, in other +words, don't use on AC (Action Cache) stores. Any store where you can +safely use `VerifySpec.verify_size = true`, this store should be safe +to use (i.e., CAS stores). + +**Example JSON5 config:** +```json5 +"size_partitioning": { + "size": "128mib", + "lower_store": { + "memory": { + "eviction_policy": { + "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" + } + } + }, + "upper_store": { + /// This store discards data larger than 128mib. + "noop": {} + } +} +``` + +**Type:** [SizePartitioningSpec](#sizepartitioningspec) + +### `grpc` + +This store will pass-through calls to another GRPC store. This store +is not designed to be used as a sub-store of another store, but it +does satisfy the interface and will likely work. + +One major GOTCHA is that some stores use a special function on this +store to get the size of the underlying object, which is only reliable +when this store is serving the a CAS store, not an AC store. If using +this store directly without being a child of any store there are no +side effects and is the most efficient way to use it. + +**Example JSON5 config:** +```json5 +"grpc": { + "instance_name": "main", + "endpoints": [ + {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} + ], + "connections_per_endpoint": "5", + "rpc_timeout_s": "5m", + "store_type": "ac", + // Static headers attached to every outgoing request to the upstream + // remote cache. Useful for fixed service-account credentials. + "headers": { + "authorization": "Bearer my-static-token" + }, + // Header names to copy from the inbound client request and forward to + // the upstream remote cache. Use this to pass through dynamic + // credentials such as a JWT sent by the build client. + "forward_headers": ["authorization", "x-custom-token"] +} +``` + +**Type:** [GrpcSpec](#grpcspec) + +### `redis_store` + +Stores data in any stores compatible with Redis APIs. + +Pairs well with `SizePartitioning` and/or `FastSlow` stores. +Ideal for accepting small object sizes as most Redis store +services have a max file upload of between 256Mb-512Mb. + +**Example JSON5 config:** +```json5 +"redis_store": { + "addresses": [ + "redis://127.0.0.1:6379/", + ], + "max_client_permits": 1000, +} +``` + +**Type:** [RedisSpec](#redisspec) + +### `noop` + +Noop store is a store that sends streams into the void and all data +retrieval will return 404 (`NotFound`). This can be useful for cases +where you may need to partition your data and part of your data needs +to be discarded. + +**Example JSON5 config:** +```json5 +"noop": {} +``` + +**Type:** [NoopSpec](#noopspec) + +### `experimental_mongo` + +Experimental `MongoDB` store implementation. + +This store uses `MongoDB` as a backend for storing data. It supports +both CAS (Content Addressable Storage) and scheduler data with +optional change streams for real-time updates. + +**Example JSON5 config:** +```json5 +"experimental_mongo": { + "connection_string": "mongodb://localhost:27017", + "database": "nativelink", + "cas_collection": "cas", + "key_prefix": "cas:", + "read_chunk_size": 65536, + "max_concurrent_uploads": 10, + "enable_change_streams": false, + "max_requests": "100" +} +``` + +**Type:** [ExperimentalMongoSpec](#experimentalmongospec) + +## WorkerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `local` + +A worker type that executes jobs locally on this machine. + +**Type:** [LocalWorkerConfig](#localworkerconfig) + +## NamedSchedulerConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## ServerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {index of server in config} | Name of the server. This is used to help identify the service for telemetry and logs. | +| `listener` | [ListenerConfig](#listenerconfig) | Yes | — | Configuration | +| `services` | [ServicesConfig](#servicesconfig) | — | — | Services to attach to server. | +| `experimental_identity_header` | [IdentityHeaderSpec](#identityheaderspec) | — | {see `IdentityHeaderSpec`} | The config related to identifying the client. | + +## OriginEventsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `publisher` | [OriginEventsPublisherSpec](#origineventspublisherspec) | Yes | — | The publisher configuration for origin events. | +| `max_event_queue_size` | integer (uint) | — | 65536 (zero defaults to this) | The maximum number of events to queue before applying back pressure. IMPORTANT: Backpressure causes all clients to slow down significantly. Zero is default. | + +## GlobalConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_open_files` | integer (uint) | Yes | 24576 (= 24 * 1024) | Maximum number of open files that can be opened at one time. This value is not strictly enforced, it is a best effort. Some internal libraries open files or read metadata from a files which do not obey this limit, however the vast majority of cases will have this limit be honored. This value must be larger than `ulimit -n` to have any effect. Any network open file descriptors is not counted in this limit, but is counted in the kernel limit. It is a good idea to set a very large `ulimit -n`. Note: This value must be greater than 10. | +| `default_digest_hash_function` | [ConfigDigestHashFunction](#configdigesthashfunction) | — | `ConfigDigestHashFunction::sha256` | Default hash function to use while uploading blobs to the CAS when not set by client. | +| `default_digest_size_health_check` | integer (uint) | — | 1024*1024 (1MiB) | Default digest size to use for health check when running diagnostics checks. Health checks are expected to use this size for filling a buffer that is used for creation of digest. | + +## CacheMetricsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | + +## MemorySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## ExperimentalCloudObjectSpec + +See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for details + +## OntapS3ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_path` | string | Yes | — | | +| `sync_interval_seconds` | integer (uint32) | Yes | — | | +| `backend` | [ExperimentalOntapS3Spec](#experimentalontaps3spec) | Yes | — | | + +## VerifySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | +| `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | + +## CompletenessCheckingSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | + +## CompressionSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | + +## DedupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | +| `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | +| `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | +| `max_concurrent_fetch_per_get` | integer (uint32) | — | 10 | Due to implementation detail, we want to prefer to download the first chunks of the file so we can stream the content out and free up some of our buffers. This configuration will be used to restrict the number of concurrent chunk downloads at a time per `get()` request. | + +## ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## FastSlowSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | +| `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | + +## ShardSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `stores` | array of [ShardConfig](#shardconfig) | Yes | — | Stores to shard the data to. | + +## FilesystemSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service startup this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e., move without copy). All files in this folder will be deleted on every startup. | +| `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | +| `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | +| `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | + +## RefSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | Name of the store under the root "stores" config object. | + +## SizePartitioningSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `size` | integer (uint64) | Yes | — | Size to partition the data on. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | + +## GrpcSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Instance name for GRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | +| `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | `0` | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. Default 1. | +| `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | +| `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | +| `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | +| `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | + +## RedisSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `addresses` | array of string | Yes | — | The hostname or IP address of the Redis server. Ex: `["redis://username:password@redis-server-url:6380/99"]` 99 Represents database ID, 6380 represents the port. | +| `response_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `command_timeout_ms` The response timeout for the Redis connection in seconds. | +| `connection_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `connection_timeout_ms` | +| `experimental_pub_sub_channel` | string | — | (Empty String / No Channel) | An optional and experimental Redis channel to publish write events to. | +| `key_prefix` | string | — | (Empty String / No Prefix) | An optional prefix to prepend to all keys in this store. | +| `mode` | [RedisMode](#redismode) | — | standard, | Set the mode Redis is operating in. | +| `broadcast_channel_capacity` | integer (uint) | — | `0` | Deprecated as redis-rs doesn't use it | +| `command_timeout_ms` | integer (uint64) | — | 10000 (10 seconds) | The amount of time in milliseconds until the Redis store considers the command to be timed out. This will trigger a retry of the command and potentially a reconnection to the Redis server. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 (3 seconds) | The amount of time in milliseconds until the Redis store considers the connection to unresponsive. This will trigger a reconnection to the Redis server. | +| `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | +| `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | +| `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it is a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | +| `max_count_per_cursor` | integer (uint64) | — | 1500 | Maximum number of items returned per cursor for the search indexes May reduce thundering herd issues with worker provisioner at higher node counts, | + +## NoopSpec + +_No fields._ + +## ExperimentalMongoSpec + +Configuration for `ExperimentalMongoDB` store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `connection_string` | string | Yes | — | `ExperimentalMongoDB` connection string. Example: <mongodb://localhost:27017> or <mongodb+srv://cluster.mongodb.net> | +| `database` | string | — | "nativelink" | The database name to use. | +| `cas_collection` | string | — | "cas" | The collection name for CAS data. | +| `scheduler_collection` | string | — | "scheduler" | The collection name for scheduler data. | +| `key_prefix` | string | — | "" | Prefix to prepend to all keys stored in `MongoDB`. | +| `read_chunk_size` | integer (uint) | — | 65536 (64KB) | The maximum amount of data to read from `MongoDB` in a single chunk (in bytes). | +| `max_concurrent_uploads` | integer (uint) | — | 10 | Deprecated, unused Maximum number of concurrent uploads allowed. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 | Connection timeout in milliseconds. | +| `command_timeout_ms` | integer (uint64) | — | 10000 | Command timeout in milliseconds. | +| `enable_change_streams` | boolean | — | false | Enable `MongoDB` change streams for real-time updates. Required for scheduler subscriptions. | +| `write_concern_w` | string | — | — | Write concern 'w' parameter. Can be a number (e.g., 1) or string (e.g., "majority"). | +| `write_concern_j` | boolean | — | — | Write concern 'j' parameter (journal acknowledgment). | +| `write_concern_timeout_ms` | integer (uint32) | — | — | Write concern timeout in milliseconds. | +| `max_requests` | integer (uint) | — | Unlimited | Limits the number of requests at any one time | + +## LocalWorkerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e., "{name}{uuidv6}"). | +| `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | +| `max_action_timeout_s` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | +| `max_upload_timeout_s` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. Value in seconds. | +| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. Value in milliseconds. | +| `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | +| `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | +| `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | +| `experimental_precondition_script` | string | — | — | An optional script to run before every action is processed on the worker. The value should be the full path to the script to execute and will pause all actions on the worker if it returns an exit code other than 0. If not set, then the worker will never pause and will continue to accept jobs according to the scheduler configuration. This is useful, for example, if the worker should not take any more actions until there is enough resource available on the machine to handle them. | +| `cas_fast_slow_store` | string | Yes | — | Underlying CAS store that the worker will use to download CAS artifacts. This store must be a `FastSlowStore`. The `fast` store must be a `FileSystemStore` because it will use hardlinks when building out the files instead of copying the files. The slow store must eventually resolve to the same store the scheduler/client uses to send job requests. | +| `upload_action_result` | [UploadActionResultConfig](#uploadactionresultconfig) | — | — | Configuration for uploading action results. | +| `work_directory` | string | Yes | — | The directory work jobs will be executed from. This directory will be fully managed by the worker service and will be purged on startup. This directory and the directory referenced in `local_filesystem_store_ref`'s `stores::FilesystemStore::content_path` must be on the same filesystem. Hardlinks will be used when placing files that are accessible to the jobs that are sourced from `local_filesystem_store_ref`'s `content_path`. | +| `platform_properties` | map of string to [WorkerProperty](#workerproperty) | Yes | — | Properties of this worker. This configuration will be sent to the scheduler and used to tell the scheduler to restrict what should be executed on this worker. | +| `additional_environment` | map of string to [EnvironmentSource](#environmentsource) | — | — | An optional mapping of environment names to set for the execution as well as those specified in the action itself. If set, will set each key as an environment variable before executing the job with the value of the environment variable being the value of the property of the action being executed of that name or the fixed value. | +| `directory_cache` | [DirectoryCacheConfig](#directorycacheconfig) | — | — | Optional directory cache configuration for improving performance by caching reconstructed input directories and using hardlinks instead of rebuilding them from CAS for every action. | +| `use_namespaces` | boolean | — | False | Whether to use namespaces to isolate the execution. This is only available on Linux. It is highly recommended as it avoids a number of issues with zombie processes and also provides additional hermeticity. If explicitly set to true and it is not supported the worker will exit with an error. | +| `use_mount_namespace` | boolean | — | False | Whether to use a mount namespace to isolate the worker root. This is only available on Linux and when `use_namespaces` is true. It is highly recommended provides additional hermeticity. If explicitly set to true and it is not supported or `use_namespaces` is not set to true the worker will exit with an error. | + +## SimpleSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `supported_platform_properties` | map of string to [PropertyType](#propertytype) | — | — | A list of supported platform properties mapped to how these properties are used when the scheduler looks for worker nodes capable of running the task. | +| `retain_completed_for_s` | integer (uint32) | — | 60 seconds | The amount of time to retain completed actions for in case a `WaitExecution` is called after the action has completed. | +| `client_action_timeout_s` | integer (uint64) | — | 60 seconds | Mark operations as completed with error if no client has updated them within this duration. | +| `worker_timeout_s` | integer (uint64) | — | 5 seconds | Remove workers from pool once the worker has not responded in this amount of time in seconds. | +| `max_action_executing_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) an action can stay in Executing state without any worker update before being timed out and re-queued. This applies regardless of worker keepalive status, catching cases where a worker is alive (sending keepalives) but stuck on a specific action. Set to 0 to disable (relies only on `worker_timeout_s`). | +| `max_job_retries` | integer (uint) | — | 3 | If a job returns an internal error or times out this many times when attempting to run on a worker the scheduler will return the last error to the client. Jobs will be retried and this configuration is to help prevent one rogue job from infinitely retrying and taking up a lot of resources when the task itself is the one causing the server to go into a bad state. | +| `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | +| `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | +| `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | + +## SchedulerGrpcSpec + +A scheduler that forwards requests to an upstream scheduler. This +is useful to use when doing some kind of local action cache or CAS away from +the main cluster of workers. In general, it's more efficient to point the +build at the main scheduler directly though. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | [GrpcEndpoint](#grpcendpoint) | Yes | — | The upstream scheduler to forward requests to. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | unlimited | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | + +## CacheLookupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | Yes | — | The reference to the action cache store used to return cached actions from rather than running them again. To prevent unintended issues, this store should probably be a `CompletenessCheckingSpec`. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use if cache lookup fails. | + +## PropertyModifierSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `modifications` | array of [PropertyModification](#propertymodification) | Yes | — | A list of modifications to perform to incoming actions for the nested scheduler. These are performed in order and blindly, so removing a property that doesn't exist is fine and overwriting an existing property is also fine. If adding properties that do not exist in the nested scheduler is not supported and will likely cause unexpected behaviour. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after modifying the properties. | + +## HistoricalResourceSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `hints_file` | string | Yes | — | JSON file containing historical resource hints keyed by Bazel `RequestMetadata` `target_id` and/or `action_mnemonic`. | +| `refresh_interval_s` | integer (uint64) | — | 30 seconds | Reload interval for `hints_file`. Set to 0 to load once. | +| `cpu_property_name` | string | — | `cpu_count` | Platform property name used for CPU minimum values. | +| `memory_property_name` | string | — | `memory_kb` | Platform property name used for memory minimum values, expressed in KiB. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after applying resource hints. | + +## ListenerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `http` + +Listener for HTTP/HTTPS/HTTP2 sockets. + +**Type:** [HttpListener](#httplistener) + +## ServicesConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | +| `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel GRPC service. | +| `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | +| `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | +| `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | +| `push` | array of [PushServiceConfig](#pushserviceconfig) | — | — | | +| `worker_api` | [WorkerApiConfig](#workerapiconfig) | — | — | This is the service used for workers to connect and communicate through. NOTE: This service should be served on a different, non-public port. In other words, `worker_api` configuration should not have any other services that are served on the same port. Doing so is a security risk, as workers have a different permission set than a client that makes the remote execution/cache requests. | +| `experimental_bep` | [BepConfig](#bepconfig) | — | — | Experimental - Build Event Protocol (BEP) configuration. This is the service that will consume build events from the client and publish them to a store for processing by an external service. | +| `admin` | [AdminConfig](#adminconfig) | — | — | This is the service for any administrative tasks. It provides a REST API endpoint for administrative purposes. | +| `health` | [HealthConfig](#healthconfig) | — | — | This is the service for health status check. | + +## IdentityHeaderSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `header_name` | string | — | "x-identity" | The name of the header to look for the identity in. | +| `required` | boolean | — | `false` | If the header is required to be set or fail the request. | + +## OriginEventsPublisherSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish nativelink events to. The store name referenced in the `stores` map in the main config. | + +## ConfigDigestHashFunction + +| Value | Description | +| --- | --- | +| `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | +| `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | + +## EvictionPolicy + +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | + +## Retry + +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, +} +``` +will result in: + +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | + +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this is not set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | + +## ExperimentalOntapS3Spec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | + +## CompressionAlgorithm + +Plus exactly one of the following variants (the key selects the variant): + +### `lz4` + +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. + +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) + +**Type:** [Lz4Config](#lz4config) + +## StoreDirection + +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | + +## ShardConfig + +Configuration for an individual shard of the store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | + +## GrpcEndpoint + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. grpc://example.com:443 or grpcs://example.com:443). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | + +## StoreType + +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | + +## RedisMode + +| Value | Description | +| --- | --- | +| `"cluster"` | Use Redis Cluster. | +| `"sentinel"` | Use Redis Sentinel. | +| `"standard"` | Use a standalone Redis server. | + +## EndpointConfig + +Generic config for an endpoint and associated configs. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `uri` | string | Yes | — | URI of the endpoint. | +| `timeout` | number (float) | — | 5 seconds | Timeout in seconds that a request should take. | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint. | + +## UploadActionResultConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | — | {No uploading is done} | Underlying AC store that the worker will use to publish execution results into. Objects placed in this store should be reachable from the scheduler/client-cas after they have finished updating. | +| `upload_ac_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `SuccessOnly` | In which situations should the results be published to the `ac_store`, if set to `SuccessOnly` then only results with an exit code of 0 will be uploaded, if set to Everything all completed results will be uploaded. | +| `historical_results_store` | string | — | {CAS store of parent} | Store to upload historical results to. This should be a CAS store if set. | +| `upload_historical_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `FailuresOnly` | In which situations should the results be published to the historical CAS. The historical CAS is where failures are published. These messages conform to the CAS key-value lookup format and are always a `HistoricalExecuteResponse` serialized message. | +| `success_message_template` | string | — | "" (no message) | Template to use for the `ExecuteResponse.message` property. This message is attached to the response before it is sent to the client. The following special variables are supported:; `digest_function`: Digest function used to calculate the action digest: `action_digest_hash`: Action digest hash: `action_digest_size`: Action digest size: `historical_results_hash`: `HistoricalExecuteResponse` digest hash: `historical_results_size`: `HistoricalExecuteResponse` digest size. | +| `failure_message_template` | string | — | "" (no message) | Same as `success_message_template` but for failure case. | + +## WorkerProperty + +Plus exactly one of the following variants (the key selects the variant): + +### `values` + +List of static values. +Note: Generally there should only ever be 1 value, but if the platform +property key is `PropertyType::Priority` it may have more than one value. + +**Type:** array of string + +### `query_cmd` + +A dynamic configuration. The string will be executed as a command +(not shell) and will be split by "\n" (new line character). + +**Type:** string + +## EnvironmentSource + +One of: + +- `property`: string — The name of the platform property in the action to get the value from. +- `value`: string — The raw value to set. +- `"from_environment"` — Take the value from the local environment corresponding to the name key +- `"timeout_millis"` — The max amount of time in milliseconds the command is allowed to run (requested by the client). +- `"side_channel_file"` — A special file path will be provided that can be used to communicate with the parent process about out-of-band information. This file will be read after the command has finished executing. Based on the contents of the file, the behavior of the result may be modified. +- `"action_directory"` — A "root" directory for the action. This directory can be used to store temporary files that are not needed after the action has completed. This directory will be purged after the action has completed. + +## DirectoryCacheConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | +| `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | +| `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | + +## PropertyType + +When the scheduler matches tasks to workers that are capable of running +the task, this value will be used to determine how the property is treated. + +One of: + +- string +- `"minimum"` — Requires the platform property to be a u64 and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that has less than this value. +- `"exact"` — Requires the platform property to be a string and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that does not have this property set to the value with exact string match. +- `"priority"` — Does not restrict on this value and instead will be passed to the worker as an informational piece. In the future this will be used by the scheduler and worker to cause the scheduler to prefer certain workers over others, but not restrict them based on these values. + +## WorkerAllocationStrategy + +When a worker is being searched for to run a job, this will be used +on how to choose which worker should run the job when multiple +workers are able to run the task. + +| Value | Description | +| --- | --- | +| `"least_recently_used"` | Prefer workers that have been least recently used to run a job. | +| `"most_recently_used"` | Prefer workers that have been most recently used to run a job. | + +## ExperimentalSimpleSchedulerBackend + +One of: + +- `"memory"` — Use an in-memory store for the scheduler. +- `redis`: [ExperimentalRedisSchedulerBackend](#experimentalredisschedulerbackend) — Use a Redis store for the scheduler. + +## SchedulerSpec + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## PropertyModification + +Plus exactly one of the following variants (the key selects the variant): + +### `add` + +Add a property to the action properties. + +**Type:** [PlatformPropertyAddition](#platformpropertyaddition) + +### `remove` + +Remove a named property from the action. + +**Type:** string + +### `replace` + +If a property is found, then replace it with another one. + +**Type:** [PlatformPropertyReplacement](#platformpropertyreplacement) + +## HttpListener + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `socket_address` | string | Yes | — | Address to listen on. Example: `127.0.0.1:8080` or `:8080` to listen to all IPs. | +| `freebind` | boolean | — | false | Allow binding `socket_address` before it is assigned locally. | +| `compression` | [HttpCompressionConfig](#httpcompressionconfig) | — | — | Data transport compression configuration to use for this service. | +| `advanced_http` | [HttpServerConfig](#httpserverconfig) | — | — | Advanced HTTP server configuration. | +| `max_decoding_message_size` | integer (uint) | — | 4 MiB | Maximum number of bytes to decode on each grpc stream chunk. | +| `tls` | [TlsConfig](#tlsconfig) | — | — | TLS configuration for this server. If not set, the server will not use TLS. | + +## CasServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `experimental_chunking` | [CasChunkingConfig](#caschunkingconfig) | — | not set — chunking RPCs are rejected, nothing is advertised, | Optional and experimental: enables the REAPI `SplitBlob`/`SpliceBlob` RPCs used by content-defined chunking clients (e.g. Bazel's `--experimental_remote_cache_chunking`). When set, the capabilities service advertises blob split/splice support and `FastCDC` 2020 parameters for this instance. When `cas_store` is a grpc store the RPCs are forwarded to the backend (which must support chunking with matching parameters); otherwise they are served locally. | + +## ActionCacheServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `ac_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## CapabilitiesServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | +| `remote_cache_compression` | boolean | — | — | Whether this instance supports Bazel remote cache compression. When enabled, the capabilities service advertises zstd wire compression and the ByteStream/CAS services accept REAPI compressed-blobs/zstd data. | + +## ExecutionServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. This value must be a CAS store reference. | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## ByteStreamServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | Name of the store in the "stores" configuration. | +| `max_bytes_per_stream` | integer (uint) | — | 64KiB | Max number of bytes to send on each grpc stream chunk. According to [https://github.com/grpc/grpc.github.io/issues/371](https://github.com/grpc/grpc.github.io/issues/371) 16KiB - 64KiB is optimal. | +| `persist_stream_on_disconnect_timeout_s` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | + +## FetchServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `fetch_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## PushServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `push_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## WorkerApiConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## BepConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish build events to. The store name referenced in the `stores` map in the main config. | + +## AdminConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/admin" | Path to register the admin API. If path is "/admin", and your domain is "example.com", you can reach the endpoint with: [http://example.com/admin](http://example.com/admin). | + +## HealthConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/status" | Path to register the health status check. If path is "/status", and your domain is "example.com", you can reach the endpoint with: [http://example.com/status](http://example.com/status). | +| `timeout_seconds` | integer (uint64) | — | 5s | Timeout on health checks. | + +## ErrorCode + +The possible error codes that might occur on an upstream request. + +| Value | Description | +| --- | --- | +| `"Cancelled"` | | +| `"Unknown"` | | +| `"InvalidArgument"` | | +| `"DeadlineExceeded"` | | +| `"NotFound"` | | +| `"AlreadyExists"` | | +| `"PermissionDenied"` | | +| `"ResourceExhausted"` | | +| `"FailedPrecondition"` | | +| `"Aborted"` | | +| `"OutOfRange"` | | +| `"Unimplemented"` | | +| `"Internal"` | | +| `"Unavailable"` | | +| `"DataLoss"` | | +| `"Unauthenticated"` | | + +## Lz4Config + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `block_size` | integer (uint32) | — | 65536 (64k) | Size of the blocks to compress. Higher values require more ram, but might yield slightly better compression ratios. | +| `max_decode_block_size` | integer (uint32) | — | value in `block_size` | Maximum size allowed to attempt to deserialize data into. This is needed because the `block_size` is embedded into the data so if there was a bad actor, they could upload an extremely large `block_size`'ed entry and we'd allocate a large amount of memory when retrieving the data. To prevent this from happening, we allow you to specify the maximum that we'll attempt to deserialize. | + +## ClientTlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ca_file` | string | — | — | Path to the certificate authority to use to validate the remote. | +| `cert_file` | string | — | — | Path to the certificate file for client authentication. | +| `key_file` | string | — | — | Path to the private key file for client authentication. | +| `use_native_roots` | boolean | — | false | If set the client will use the native roots for TLS connections. | + +## UploadCacheResultsStrategy + +| Value | Description | +| --- | --- | +| `"success_only"` | Only upload action results with an exit code of 0. | +| `"never"` | Don't upload any action results. | +| `"everything"` | Upload all action results that complete. | +| `"failures_only"` | Only upload action results that fail. | + +## ExperimentalRedisSchedulerBackend + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `redis_store` | string | Yes | — | A reference to the Redis store to use for the scheduler. Note: This MUST resolve to a `RedisSpec`. | + +## PlatformPropertyAddition + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to add. | +| `value` | string | Yes | — | The value to assign to the property. | + +## PlatformPropertyReplacement + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to replace. | +| `value` | string | — | — | The value to match against, if unset then any instance matches. | +| `new_name` | string | Yes | — | The new name of the property. | +| `new_value` | string | — | — | The value to assign to the property, if unset will remain the same. | + +## HttpCompressionConfig + +Note: Compressing data in the cloud rarely has a benefit, since most +cloud providers have very high bandwidth backplanes. However, for +clients not inside the data center, it might be a good idea to +compress data to and from the cloud. This will however come at a high +CPU and performance cost. If you are making remote execution share the +same CAS/AC servers as client's remote cache, you can create multiple +services with different compression settings that are served on +different ports. Then configure the non-cloud clients to use one port +and cloud-clients to use another. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `send_compression_algorithm` | [HttpCompressionAlgorithm](#httpcompressionalgorithm) | — | `HttpCompressionAlgorithm::None` | The compression algorithm that the server will use when sending responses to clients. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | +| `accepted_compression_algorithms` | array of [HttpCompressionAlgorithm](#httpcompressionalgorithm) | Yes | {no supported compression} | The compression algorithm that the server will accept from clients. The server will broadcast the supported compression algorithms to clients and the client will choose which compression algorithm to use. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | + +## HttpServerConfig + +Advanced HTTP configuration. These generally should not be set. +For documentation on these settings, see the hyper documentation: +See: [hyper HTTP server docs](https://docs.rs/hyper/latest/hyper/server/conn/struct.Http.html) + +Note: All of these default to the default values from hyper unless otherwise +specified. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `http2_keep_alive_interval` | integer (uint32) | — | — | Interval to send keep-alive pings via HTTP2. Note: This is in seconds. | +| `experimental_http2_max_pending_accept_reset_streams` | integer (uint32) | — | — | | +| `experimental_http2_initial_stream_window_size` | integer (uint32) | — | — | | +| `experimental_http2_initial_connection_window_size` | integer (uint32) | — | — | | +| `experimental_http2_adaptive_window` | boolean | — | — | | +| `experimental_http2_max_frame_size` | integer (uint32) | — | — | | +| `experimental_http2_max_concurrent_streams` | integer (uint32) | — | — | | +| `experimental_http2_keep_alive_timeout_s` | integer (uint32) | — | — | | +| `experimental_http2_max_send_buf_size` | integer (uint32) | — | — | | +| `experimental_http2_enable_connect_protocol` | boolean | — | — | | +| `experimental_http2_max_header_list_size` | integer (uint32) | — | — | | + +## TlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cert_file` | string | Yes | — | Path to the certificate file. | +| `key_file` | string | Yes | — | Path to the private key file. | +| `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | +| `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | + +## CasChunkingConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | string | — | — | The store name referenced in the `stores` map in the main config used to persist blob-to-chunks layouts. Keys are the digests of the original blobs and values are serialized chunk layouts (which do not hash to those digests), so this store MUST NOT perform content digest verification and MUST NOT be the same store as `cas_store` — writing layouts into the CAS would overwrite blob content. Using the same store name as `cas_store` is rejected at startup. | +| `avg_chunk_size_bytes` | integer (uint64) | — | 524288 (512 KiB) | The average chunk size in bytes advertised to clients through the `FastCDC` 2020 capability parameters and used for server-side chunking in `SplitBlob`. Clients derive the minimum and maximum chunk sizes from this value (avg / 4 and avg * 4). The value must be between 1 KiB and 1 MiB. | +| `max_chunk_count` | integer (uint64) | — | 50000 | Maximum number of chunks accepted in a `SpliceBlob` request or produced by on-demand chunking in `SplitBlob`. Blobs that would produce more chunks are served without chunking (`SplitBlob` returns `NOT_FOUND` and clients fall back to a regular download). This bounds the size of stored chunk layouts and of `SplitBlobResponse` messages (roughly 80-140 bytes per chunk). At the default average chunk size the default cap supports blobs up to ~25 GiB; note that values above ~50000 may produce responses that exceed default gRPC message size limits on clients. | + +## CapabilitiesRemoteExecutionConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | Scheduler used to configure the capabilities of remote execution. | + +## HttpCompressionAlgorithm + +| Value | Description | +| --- | --- | +| `"none"` | No compression. | +| `"gzip"` | Zlib compression. | + +## Reading the source + +If anything here disagrees with the binary, the source wins: + +- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.1/nativelink-config/src/stores.rs) +- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.1/nativelink-config/src/cas_server.rs) +- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.1/nativelink-config/src/schedulers.rs) diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.6.2.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.2.mdx new file mode 100644 index 000000000..beb6bb0a7 --- /dev/null +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.2.mdx @@ -0,0 +1,1537 @@ +--- +title: Configuration reference +description: Every knob in the NativeLink JSON5 configuration — types, defaults, and links to source, autogenerated from the Rust config crate. +full: true +--- + +{/* AUTOGENERATED — do not edit by hand. + Source: nativelink-config @ v1.6.2 (9717f2fb) + Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} + + + +This is the canonical NativeLink configuration reference for **v1.6.2**. +It is autogenerated from the Rust config crate +([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.6.2/nativelink-config/src)) via the `build-schema` binary, so +it can never drift from what the binary actually deserializes. + +## Top-level fields + +The root object (`CasConfig`) accepts the following fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stores` | array of [NamedStoreConfig](#namedstoreconfig) | Yes | List of stores available to use in this config. The keys can be used in other configs when needing to reference a store. | +| `workers` | array of [WorkerConfig](#workerconfig) | — | Worker configurations used to execute jobs. | +| `schedulers` | array of [NamedSchedulerConfig](#namedschedulerconfig) | — | List of schedulers available to use in this config. The keys can be used in other configs when needing to reference a scheduler. | +| `servers` | array of [ServerConfig](#serverconfig) | Yes | Servers to setup for this process. | +| `experimental_origin_events` | [OriginEventsSpec](#origineventsspec) | — | Experimental - Origin events configuration. This is the service that will collect and publish nativelink events to a store for processing by an external service. | +| `global` | [GlobalConfig](#globalconfig) | — | Any global configurations that apply to all modules live here. | + +## Configuration types + +Every type reachable from the root configuration, in reading order. + +## NamedStoreConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `cache_metrics` + +Cache metrics store wraps another store and emits low-cardinality +OpenTelemetry cache operation metrics for the wrapped store. + +This wrapper is opt-in. Stores that are not explicitly wrapped by +`cache_metrics` are constructed exactly as they are without this +wrapper and do not pay its hot-path timing or recording cost. + +**Example JSON5 config:** +```json5 +"cache_metrics": { + "cache_type": "cas", + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-cas", + "temp_path": "~/.cache/nativelink/tmp_path-cas" + } + } +} +``` + +**Type:** [CacheMetricsSpec](#cachemetricsspec) + +### `memory` + +Memory store will store all data in a hash map in memory. + +**Example JSON5 config:** +```json5 +"memory": { + "eviction_policy": { + "max_bytes": "10mb", + } +} +``` + +**Type:** [MemorySpec](#memoryspec) + +### `experimental_cloud_object_store` + +A generic blob store that will store files on the cloud +provider. This configuration will never delete files, so you are +responsible for purging old files in other ways. +It supports the following backends: + +1. **Amazon S3:** + S3 store will use Amazon's S3 service as a backend to store + the files. This configuration can be used to share files + across multiple instances. Uses system certificates for TLS + verification via `rustls-platform-verifier`. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "aws", + "region": "eu-north-1", + "bucket": "crossplane-bucket-af79aeca9", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +2. **Google Cloud Storage:** + GCS store uses Google's GCS service as a backend to store + the files. This configuration can be used to share files + across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "gcs", + "bucket": "test-bucket", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +3. **Azure Blob Store:** + Azure Blob store will use Microsoft's Azure Blob service as a + backend to store the files. This configuration can be used to + share files across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "azure", + "account_name": "cloudshell1393657559", + "container": "simple-test-container", + "key_prefix": "folder/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend + to store files. This store is specifically configured for ONTAP's S3 requirements + including custom TLS configuration, credentials management, and proper vserver + configuration. + + This store uses AWS environment variables for credentials: + - `AWS_ACCESS_KEY_ID` + - `AWS_SECRET_ACCESS_KEY` + - `AWS_DEFAULT_REGION` + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "ontap", + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "root_certificates": "/path/to/certs.pem", // Optional + "key_prefix": "test-prefix/", // Optional + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +5. **Cloudflare R2:** + R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + S3 API, so this is a thin wrapper that derives the account-scoped + endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + Storage API. The path-style endpoint is derived from your Object + Storage `namespace` and `region` as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + Authenticate with a Customer Secret Key (Access Key/Secret Key pair + created under User Settings -> Customer secret keys in the OCI + console); the secret cannot be retrieved after generation, so read + it from an env var via shellexpand. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + ``` + +**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) + +### `ontap_s3_existence_cache` + +ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store +to optimize repeated existence checks. It maintains an in-memory cache of object +digests and periodically syncs this cache to disk for persistence. + +The cache helps reduce latency for repeated calls to check object existence, +while still ensuring eventual consistency with the underlying ONTAP S3 store. + +Example JSON5 config: +```json5 +"ontap_s3_existence_cache": { + "index_path": "/path/to/cache/index.json", + "sync_interval_seconds": 300, + "backend": { + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "key_prefix": "test-prefix/" + } +} +``` + +**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) + +### `verify` + +Verify store is used to apply verifications to an underlying +store implementation. It is strongly encouraged to validate +as much data as you can before accepting data from a client, +failing to do so may cause the data in the store to be +populated with invalid data causing all kinds of problems. + +The suggested configuration is to have the CAS validate the +hash and size and the AC validate nothing. + +**Example JSON5 config:** +```json5 +"verify": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb" + } + }, + }, + "verify_size": true, + "verify_hash": true +} +``` + +**Type:** [VerifySpec](#verifyspec) + +### `completeness_checking` + +Completeness checking store verifies if the +output files & folders exist in the CAS before forwarding +the request to the underlying store. +Note: This store should only be used on AC stores. + +**Example JSON5 config:** +```json5 +"completeness_checking": { + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-ac", + "temp_path": "~/.cache/nativelink/tmp_path-ac", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "cas_store": { + "ref_store": { + "name": "CAS_MAIN_STORE" + } + } +} +``` + +**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) + +### `compression` + +A compression store that will compress the data inbound and +outbound. There will be a non-trivial cost to compress and +decompress the data, but in many cases if the final store is +a store that requires network transport and/or storage space +is a concern it is often faster and more efficient to use this +store before those stores. + +**Example JSON5 config:** +```json5 +"compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-cas", + "temp_path": "/tmp/nativelink/data/tmp_path-cas", + "eviction_policy": { + "max_bytes": "2gb", + } + } + } +} +``` + +**Type:** [CompressionSpec](#compressionspec) + +### `dedup` + +A dedup store will take the inputs and run a rolling hash +algorithm on them to slice the input into smaller parts then +run a sha256 algorithm on the slice and if the object doesn't +already exist, upload the slice to the `content_store` using +a new digest of just the slice. Once all parts exist, an +Action-Cache-like digest will be built and uploaded to the +`index_store` which will contain a reference to each +chunk/digest of the uploaded file. Downloading a request will +first grab the index from the `index_store`, and forward the +download content of each chunk as if it were one file. + +This store is exceptionally good when the following conditions +are met: +* Content is mostly the same (inserts, updates, deletes are ok) +* Content is not compressed or encrypted +* Uploading or downloading from `content_store` is the bottleneck. + +Note: This store pairs well when used with `CompressionSpec` as +the `content_store`, but never put `DedupSpec` as the backend of +`CompressionSpec` as it will negate all the gains. + +Note: When running `.has()` on this store, it will only check +to see if the entry exists in the `index_store` and not check +if the individual chunks exist in the `content_store`. + +**Example JSON5 config:** +```json5 +"dedup": { + "index_store": { + "memory": { + "eviction_policy": { + "max_bytes": "1GB", + } + } + }, + "content_store": { + "compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "fast_slow": { + "fast": { + "memory": { + "eviction_policy": { + "max_bytes": "500MB", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-content", + "temp_path": "/tmp/nativelink/data/tmp_path-content", + "eviction_policy": { + "max_bytes": "2gb" + } + } + } + } + } + } + } +} +``` + +**Type:** [DedupSpec](#dedupspec) + +### `existence_cache` + +Existence store will wrap around another store and cache calls +to has so that subsequent `has_with_results` calls will be +faster. This is useful for cases when you have a store that +is slow to respond to has calls. +Note: This store should only be used on CAS stores. + +**Example JSON5 config:** +```json5 +"existence_cache": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + // Note this is the existence store policy, not the backend policy + "eviction_policy": { + "max_seconds": 100, + } +} +``` + +**Type:** [ExistenceCacheSpec](#existencecachespec) + +### `fast_slow` + +`FastSlow` store will first try to fetch the data from the `fast` +store and then if it does not exist try the `slow` store. +When the object does exist in the `slow` store, it will copy +the data to the `fast` store while returning the data. +This store should be thought of as a store that "buffers" +the data to the `fast` store. +On uploads it will mirror data to both `fast` and `slow` stores. + +WARNING: If you need data to always exist in the `slow` store +for something like remote execution, be careful because this +store will never check to see if the objects exist in the +`slow` store if it exists in the `fast` store (i.e. it assumes +that if an object exists in the `fast` store it will exist in +the `slow` store). + +***Example JSON5 config:*** +```json5 +"fast_slow": { + "fast": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + } +} +``` + +**Type:** [FastSlowSpec](#fastslowspec) + +### `shard` + +Shards the data to multiple stores. This is useful for cases +when you want to distribute the load across multiple stores. +The digest hash is used to determine which store to send the +data to. + +**Example JSON5 config:** +```json5 +"shard": { + "stores": [ + { + "store": { + "memory": { + "eviction_policy": { + "max_bytes": "10mb" + }, + }, + }, + "weight": 1 + }] +} +``` + +**Type:** [ShardSpec](#shardspec) + +### `filesystem` + +Stores the data on the filesystem. This store is designed for +local persistent storage. Restarts of this program should restore +the previous state, meaning anything uploaded will be persistent +as long as the filesystem integrity holds. + +**Example JSON5 config:** +```json5 +"filesystem": { + "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", + "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", + "eviction_policy": { + "max_bytes": "10gb", + } +} +``` + +**Type:** [FilesystemSpec](#filesystemspec) + +### `ref_store` + +Store used to reference a store in the root store manager. +This is useful for cases when you want to share a store in different +nested stores. Example, you may want to share the same memory store +used for the action cache, but use a `FastSlowSpec` and have the fast +store also share the memory store for efficiency. + +**Example JSON5 config:** +```json5 +"ref_store": { + "name": "FS_CONTENT_STORE" +} +``` + +**Type:** [RefSpec](#refspec) + +### `size_partitioning` + +Uses the size field of the digest to separate which store to send the +data. This is useful for cases when you'd like to put small objects +in one store and large objects in another store. This should only be +used if the size field is the real size of the content, in other +words, don't use on AC (Action Cache) stores. Any store where you can +safely use `VerifySpec.verify_size = true`, this store should be safe +to use (i.e. CAS stores). + +**Example JSON5 config:** +```json5 +"size_partitioning": { + "size": "128mib", + "lower_store": { + "memory": { + "eviction_policy": { + "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" + } + } + }, + "upper_store": { + /// This store discards data larger than 128mib. + "noop": {} + } +} +``` + +**Type:** [SizePartitioningSpec](#sizepartitioningspec) + +### `grpc` + +This store will pass-through calls to another gRPC store. This store +is not designed to be used as a sub-store of another store, but it +does satisfy the interface and will likely work. + +One major GOTCHA is that some stores use a special function on this +store to get the size of the underlying object, which is only reliable +when this store is serving the a CAS store, not an AC store. If using +this store directly without being a child of any store there are no +side effects and is the most efficient way to use it. + +**Example JSON5 config:** +```json5 +"grpc": { + "instance_name": "main", + "endpoints": [ + {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} + ], + "connections_per_endpoint": "5", + "rpc_timeout_s": "5m", + "store_type": "ac", + // Static headers attached to every outgoing request to the upstream + // remote cache. Useful for fixed service-account credentials. + "headers": { + "authorization": "Bearer my-static-token" + }, + // Header names to copy from the inbound client request and forward to + // the upstream remote cache. Use this to pass through dynamic + // credentials such as a JWT sent by the build client. + "forward_headers": ["authorization", "x-custom-token"] +} +``` + +**Type:** [GrpcSpec](#grpcspec) + +### `redis_store` + +Stores data in any stores compatible with Redis APIs. + +Pairs well with `SizePartitioning` and/or `FastSlow` stores. +Ideal for accepting small object sizes as most Redis store +services have a max file upload of between 256Mb-512Mb. + +**Example JSON5 config:** +```json5 +"redis_store": { + "addresses": [ + "redis://127.0.0.1:6379/", + ], + "max_client_permits": 1000, +} +``` + +**Type:** [RedisSpec](#redisspec) + +### `noop` + +Noop store is a store that sends streams into the void and all data +retrieval will return 404 (`NotFound`). This can be useful for cases +where you may need to partition your data and part of your data needs +to be discarded. + +**Example JSON5 config:** +```json5 +"noop": {} +``` + +**Type:** [NoopSpec](#noopspec) + +### `experimental_mongo` + +Experimental `MongoDB` store implementation. + +This store uses `MongoDB` as a backend for storing data. It supports +both CAS (Content Addressable Storage) and scheduler data with +optional change streams for real-time updates. + +**Example JSON5 config:** +```json5 +"experimental_mongo": { + "connection_string": "mongodb://localhost:27017", + "database": "nativelink", + "cas_collection": "cas", + "key_prefix": "cas:", + "read_chunk_size": 65536, + "max_concurrent_uploads": 10, + "enable_change_streams": false, + "max_requests": "100" +} +``` + +**Type:** [ExperimentalMongoSpec](#experimentalmongospec) + +## WorkerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `local` + +A worker type that executes jobs locally on this machine. + +**Type:** [LocalWorkerConfig](#localworkerconfig) + +## NamedSchedulerConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## ServerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {index of server in config} | Name of the server. This is used to help identify the service for telemetry and logs. | +| `listener` | [ListenerConfig](#listenerconfig) | Yes | — | Configuration | +| `services` | [ServicesConfig](#servicesconfig) | — | — | Services to attach to server. | +| `experimental_identity_header` | [IdentityHeaderSpec](#identityheaderspec) | — | {see `IdentityHeaderSpec`} | The config related to identifying the client. | + +## OriginEventsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `publisher` | [OriginEventsPublisherSpec](#origineventspublisherspec) | Yes | — | The publisher configuration for origin events. | +| `max_event_queue_size` | integer (uint) | — | 65536 (zero defaults to this) | The maximum number of events to queue before applying back pressure. IMPORTANT: Backpressure causes all clients to slow down significantly. Zero is default. | + +## GlobalConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_open_files` | integer (uint) | Yes | 24576 (= 24 * 1024) | Maximum number of open files that can be opened at one time. This value is not strictly enforced, it is a best effort. Some internal libraries open files or read metadata from a files which do not obey this limit, however the vast majority of cases will have this limit be honored. This value must be larger than `ulimit -n` to have any effect. Any network open file descriptors is not counted in this limit, but is counted in the kernel limit. It is a good idea to set a very large `ulimit -n`. Note: This value must be greater than 10. | +| `default_digest_hash_function` | [ConfigDigestHashFunction](#configdigesthashfunction) | — | `ConfigDigestHashFunction::sha256` | Default hash function to use while uploading blobs to the CAS when not set by client. | +| `default_digest_size_health_check` | integer (uint) | — | 1024*1024 (1MiB) | Default digest size to use for health check when running diagnostics checks. Health checks are expected to use this size for filling a buffer that is used for creation of digest. | + +## CacheMetricsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | + +## MemorySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## ExperimentalCloudObjectSpec + +See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for details + +## OntapS3ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_path` | string | Yes | — | | +| `sync_interval_seconds` | integer (uint32) | Yes | — | | +| `backend` | [ExperimentalOntapS3Spec](#experimentalontaps3spec) | Yes | — | | + +## VerifySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | +| `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | + +## CompletenessCheckingSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | + +## CompressionSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | + +## DedupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | +| `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | +| `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | +| `max_concurrent_fetch_per_get` | integer (uint32) | — | 10 | Due to implementation detail, we want to prefer to download the first chunks of the file so we can stream the content out and free up some of our buffers. This configuration will be used to restrict the number of concurrent chunk downloads at a time per `get()` request. | + +## ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## FastSlowSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | +| `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | + +## ShardSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `stores` | array of [ShardConfig](#shardconfig) | Yes | — | Stores to shard the data to. | + +## FilesystemSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service boot this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e. move without copy). All files in this folder will be deleted on every startup. | +| `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | +| `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | +| `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | + +## RefSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | Name of the store under the root "stores" config object. | + +## SizePartitioningSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `size` | integer (uint64) | Yes | — | Size to partition the data on. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | + +## GrpcSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Instance name for gRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | +| `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | +| `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | +| `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | +| `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | +| `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | +| `experimental_read_batching` | [GrpcReadBatchingConfig](#grpcreadbatchingconfig) | — | unset (disabled) | Optional and experimental: coalesce small-blob reads into `BatchReadBlobs` RPCs instead of issuing one `ByteStream` `Read` stream per blob. Each `ByteStream` read carries a fixed per-RPC cost, so batching many small reads into a single `BatchReadBlobs` request can dramatically reduce read latency for small blobs. | + +## RedisSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `addresses` | array of string | Yes | — | The hostname or IP address of the Redis server. Ex: `["redis://username:password@redis-server-url:6380/99"]` 99 Represents database ID, 6380 represents the port. | +| `response_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `command_timeout_ms` The response timeout for the Redis connection in seconds. | +| `connection_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `connection_timeout_ms` | +| `experimental_pub_sub_channel` | string | — | (Empty String / No Channel) | An optional and experimental Redis channel to publish write events to. | +| `key_prefix` | string | — | (Empty String / No Prefix) | An optional prefix to prepend to all keys in this store. | +| `mode` | [RedisMode](#redismode) | — | standard, | Set the mode Redis is operating in. | +| `broadcast_channel_capacity` | integer (uint) | — | `0` | Deprecated as redis-rs doesn't use it | +| `command_timeout_ms` | integer (uint64) | — | 10000 (10 seconds) | The amount of time in milliseconds until the Redis store considers the command to be timed out. This will trigger a retry of the command and potentially a reconnection to the Redis server. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 (3 seconds) | The amount of time in milliseconds until the Redis store considers the connection to unresponsive. This will trigger a reconnection to the Redis server. | +| `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | +| `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | +| `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it's a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | +| `max_count_per_cursor` | integer (uint64) | — | 1500 | Maximum number of items returned per cursor for the search indexes May reduce thundering herd issues with worker provisioner at higher node counts, | + +## NoopSpec + +_No fields._ + +## ExperimentalMongoSpec + +Configuration for `ExperimentalMongoDB` store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `connection_string` | string | Yes | — | `ExperimentalMongoDB` connection string. Example: <mongodb://localhost:27017> or <mongodb+srv://cluster.mongodb.net> | +| `database` | string | — | "nativelink" | The database name to use. | +| `cas_collection` | string | — | "cas" | The collection name for CAS data. | +| `scheduler_collection` | string | — | "scheduler" | The collection name for scheduler data. | +| `key_prefix` | string | — | "" | Prefix to prepend to all keys stored in `MongoDB`. | +| `read_chunk_size` | integer (uint) | — | 65536 (64KB) | The maximum amount of data to read from `MongoDB` in a single chunk (in bytes). | +| `max_concurrent_uploads` | integer (uint) | — | 10 | Deprecated, unused Maximum number of concurrent uploads allowed. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 | Connection timeout in milliseconds. | +| `command_timeout_ms` | integer (uint64) | — | 10000 | Command timeout in milliseconds. | +| `enable_change_streams` | boolean | — | false | Enable `MongoDB` change streams for real-time updates. Required for scheduler subscriptions. | +| `write_concern_w` | string | — | — | Write concern 'w' parameter. Can be a number (e.g., 1) or string (e.g., "majority"). | +| `write_concern_j` | boolean | — | — | Write concern 'j' parameter (journal acknowledgment). | +| `write_concern_timeout_ms` | integer (uint32) | — | — | Write concern timeout in milliseconds. | +| `max_requests` | integer (uint) | — | Unlimited | Limits the number of requests at any one time | + +## LocalWorkerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e. "{name}{uuidv6}"). | +| `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | +| `max_action_timeout_s` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | +| `max_upload_timeout_s` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. Value in seconds. | +| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. Value in milliseconds. | +| `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | +| `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | +| `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | +| `experimental_precondition_script` | string | — | — | An optional script to run before every action is processed on the worker. The value should be the full path to the script to execute and will pause all actions on the worker if it returns an exit code other than 0. If not set, then the worker will never pause and will continue to accept jobs according to the scheduler configuration. This is useful, for example, if the worker should not take any more actions until there is enough resource available on the machine to handle them. | +| `cas_fast_slow_store` | string | Yes | — | Underlying CAS store that the worker will use to download CAS artifacts. This store must be a `FastSlowStore`. The `fast` store must be a `FileSystemStore` because it will use hardlinks when building out the files instead of copying the files. The slow store must eventually resolve to the same store the scheduler/client uses to send job requests. | +| `upload_action_result` | [UploadActionResultConfig](#uploadactionresultconfig) | — | — | Configuration for uploading action results. | +| `work_directory` | string | Yes | — | The directory work jobs will be executed from. This directory will be fully managed by the worker service and will be purged on startup. This directory and the directory referenced in `local_filesystem_store_ref`'s `stores::FilesystemStore::content_path` must be on the same filesystem. Hardlinks will be used when placing files that are accessible to the jobs that are sourced from `local_filesystem_store_ref`'s `content_path`. | +| `platform_properties` | map of string to [WorkerProperty](#workerproperty) | Yes | — | Properties of this worker. This configuration will be sent to the scheduler and used to tell the scheduler to restrict what should be executed on this worker. | +| `additional_environment` | map of string to [EnvironmentSource](#environmentsource) | — | — | An optional mapping of environment names to set for the execution as well as those specified in the action itself. If set, will set each key as an environment variable before executing the job with the value of the environment variable being the value of the property of the action being executed of that name or the fixed value. | +| `directory_cache` | [DirectoryCacheConfig](#directorycacheconfig) | — | — | Optional directory cache configuration for improving performance by caching reconstructed input directories and using hardlinks instead of rebuilding them from CAS for every action. | +| `use_namespaces` | boolean | — | False | Whether to use namespaces to isolate the execution. This is only available on Linux. It is highly recommended as it avoids a number of issues with zombie processes and also provides additional hermeticity. If explicitly set to true and it is not supported the worker will exit with an error. | +| `use_mount_namespace` | boolean | — | False | Whether to use a mount namespace to isolate the worker root. This is only available on Linux and when `use_namespaces` is true. It is highly recommended provides additional hermeticity. If explicitly set to true and it is not supported or `use_namespaces` is not set to true the worker will exit with an error. | + +## SimpleSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `supported_platform_properties` | map of string to [PropertyType](#propertytype) | — | — | A list of supported platform properties mapped to how these properties are used when the scheduler looks for worker nodes capable of running the task. | +| `retain_completed_for_s` | integer (uint32) | — | 60 seconds | The amount of time to retain completed actions for in case a `WaitExecution` is called after the action has completed. | +| `client_action_timeout_s` | integer (uint64) | — | 60 seconds | Mark operations as completed with error if no client has updated them within this duration. | +| `worker_timeout_s` | integer (uint64) | — | 5 seconds | Remove workers from pool once the worker has not responded in this amount of time in seconds. | +| `max_action_executing_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) an action can stay in Executing state without any worker update before being timed out and re-queued. This applies regardless of worker keepalive status, catching cases where a worker is alive (sending keepalives) but stuck on a specific action. Set to 0 to disable (relies only on `worker_timeout_s`). | +| `max_job_retries` | integer (uint) | — | 3 | If a job returns an internal error or times out this many times when attempting to run on a worker the scheduler will return the last error to the client. Jobs will be retried and this configuration is to help prevent one rogue job from infinitely retrying and taking up a lot of resources when the task itself is the one causing the server to go into a bad state. | +| `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | +| `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | +| `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | +| `fallback_match_interval_s` | integer (int64) | — | `5` | Every N seconds, run a worker matching pass even if no task or worker change notification arrived. This is a safety net for missed notifications and for scheduler backends with eventually consistent searches (for example Redis), where an operation that was re-queued may not be visible to the search triggered by its own notification. Without this, such an operation can stay queued until an unrelated event triggers another matching pass. Defaults to 5s. Zero or any negative value disables it. | + +## SchedulerGrpcSpec + +A scheduler that forwards requests to an upstream scheduler. This +is useful to use when doing some kind of local action cache or CAS away from +the main cluster of workers. In general, it's more efficient to point the +build at the main scheduler directly though. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | [GrpcEndpoint](#grpcendpoint) | Yes | — | The upstream scheduler to forward requests to. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | unlimited | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | + +## CacheLookupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | Yes | — | The reference to the action cache store used to return cached actions from rather than running them again. To prevent unintended issues, this store should probably be a `CompletenessCheckingSpec`. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use if cache lookup fails. | + +## PropertyModifierSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `modifications` | array of [PropertyModification](#propertymodification) | Yes | — | A list of modifications to perform to incoming actions for the nested scheduler. These are performed in order and blindly, so removing a property that doesn't exist is fine and overwriting an existing property is also fine. If adding properties that do not exist in the nested scheduler is not supported and will likely cause unexpected behaviour. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after modifying the properties. | + +## HistoricalResourceSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `hints_file` | string | Yes | — | JSON file containing historical resource hints keyed by Bazel `RequestMetadata` `target_id` and/or `action_mnemonic`. | +| `refresh_interval_s` | integer (uint64) | — | 30 seconds | Reload interval for `hints_file`. Set to 0 to load once. | +| `cpu_property_name` | string | — | `cpu_count` | Platform property name used for CPU minimum values. | +| `memory_property_name` | string | — | `memory_kb` | Platform property name used for memory minimum values, expressed in KiB. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after applying resource hints. | + +## ListenerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `http` + +Listener for HTTP/HTTPS/HTTP2 sockets. + +**Type:** [HttpListener](#httplistener) + +## ServicesConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | +| `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel gRPC service. | +| `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | +| `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | +| `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | +| `push` | array of [PushServiceConfig](#pushserviceconfig) | — | — | | +| `worker_api` | [WorkerApiConfig](#workerapiconfig) | — | — | This is the service used for workers to connect and communicate through. NOTE: This service should be served on a different, non-public port. In other words, `worker_api` configuration should not have any other services that are served on the same port. Doing so is a security risk, as workers have a different permission set than a client that makes the remote execution/cache requests. | +| `experimental_bep` | [BepConfig](#bepconfig) | — | — | Experimental - Build Event Protocol (BEP) configuration. This is the service that will consume build events from the client and publish them to a store for processing by an external service. | +| `admin` | [AdminConfig](#adminconfig) | — | — | This is the service for any administrative tasks. It provides a REST API endpoint for administrative purposes. | +| `health` | [HealthConfig](#healthconfig) | — | — | This is the service for health status check. | + +## IdentityHeaderSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `header_name` | string | — | "x-identity" | The name of the header to look for the identity in. | +| `required` | boolean | — | `false` | If the header is required to be set or fail the request. | + +## OriginEventsPublisherSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish nativelink events to. The store name referenced in the `stores` map in the main config. | + +## ConfigDigestHashFunction + +| Value | Description | +| --- | --- | +| `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | +| `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | + +## EvictionPolicy + +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | + +## Retry + +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, +} +``` +will result in: + +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | + +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this isn't set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | + +## ExperimentalOntapS3Spec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | + +## CompressionAlgorithm + +Plus exactly one of the following variants (the key selects the variant): + +### `lz4` + +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. + +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) + +**Type:** [Lz4Config](#lz4config) + +## StoreDirection + +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | + +## ShardConfig + +Configuration for an individual shard of the store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | + +## GrpcEndpoint + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. `grpc(s)://example.com:443`). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | + +## StoreType + +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | + +## GrpcReadBatchingConfig + +Configuration for experimental small-blob read coalescing in a gRPC +store. See [`GrpcSpec::experimental_read_batching`]. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_blob_size_bytes` | integer (uint64) | — | 131072 (128 KiB) | Only blobs at or below this size (in bytes) are eligible for batching. Larger blobs always use the `ByteStream` `Read` path. | +| `max_batch_bytes` | integer (uint64) | — | 3145728 (3 MiB) | Maximum total payload bytes packed into a single `BatchReadBlobs` request. This should leave headroom under the 4 MiB default gRPC message limit for protobuf framing overhead. | +| `dispatch_slots` | integer (uint) | — | 4 | Maximum number of concurrent `BatchReadBlobs` RPCs dispatched by the coalescer. Must be greater than zero. | +| `max_queued_bytes` | integer (uint64) | — | 33554432 (32 MiB) | Bound on the number of payload bytes waiting in the coalescer queue. When exceeded, new read requests bypass batching and fall back to the regular `ByteStream` `Read` path instead of blocking. | + +## RedisMode + +| Value | Description | +| --- | --- | +| `"cluster"` | Use Redis Cluster. | +| `"sentinel"` | Use Redis Sentinel. | +| `"standard"` | Use a standalone Redis server. | + +## EndpointConfig + +Generic config for an endpoint and associated configs. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `uri` | string | Yes | — | URI of the endpoint. | +| `timeout` | number (float) | — | 5 seconds | Timeout in seconds that a request should take. | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint. | + +## UploadActionResultConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | — | {No uploading is done} | Underlying AC store that the worker will use to publish execution results into. Objects placed in this store should be reachable from the scheduler/client-cas after they have finished updating. | +| `upload_ac_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `SuccessOnly` | In which situations should the results be published to the `ac_store`, if set to `SuccessOnly` then only results with an exit code of 0 will be uploaded, if set to Everything all completed results will be uploaded. | +| `historical_results_store` | string | — | {CAS store of parent} | Store to upload historical results to. This should be a CAS store if set. | +| `upload_historical_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `FailuresOnly` | In which situations should the results be published to the historical CAS. The historical CAS is where failures are published. These messages conform to the CAS key-value lookup format and are always a `HistoricalExecuteResponse` serialized message. | +| `success_message_template` | string | — | "" (no message) | Template to use for the `ExecuteResponse.message` property. This message is attached to the response before it is sent to the client. The following special variables are supported:; `digest_function`: Digest function used to calculate the action digest: `action_digest_hash`: Action digest hash: `action_digest_size`: Action digest size: `historical_results_hash`: `HistoricalExecuteResponse` digest hash: `historical_results_size`: `HistoricalExecuteResponse` digest size. | +| `failure_message_template` | string | — | "" (no message) | Same as `success_message_template` but for failure case. | + +## WorkerProperty + +Plus exactly one of the following variants (the key selects the variant): + +### `values` + +List of static values. +Note: Generally there should only ever be 1 value, but if the platform +property key is `PropertyType::Priority` it may have more than one value. + +**Type:** array of string + +### `query_cmd` + +A dynamic configuration. The string will be executed as a command +(not shell) and will be split by "\n" (new line character). + +**Type:** string + +## EnvironmentSource + +One of: + +- `property`: string — The name of the platform property in the action to get the value from. +- `value`: string — The raw value to set. +- `"from_environment"` — Take the value from the local environment corresponding to the name key +- `"timeout_millis"` — The max amount of time in milliseconds the command is allowed to run (requested by the client). +- `"side_channel_file"` — A special file path will be provided that can be used to communicate with the parent process about out-of-band information. This file will be read after the command has finished executing. Based on the contents of the file, the behavior of the result may be modified. +- `"action_directory"` — A "root" directory for the action. This directory can be used to store temporary files that are not needed after the action has completed. This directory will be purged after the action has completed. + +## DirectoryCacheConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | +| `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | +| `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | +| `experimental_subtree_caching` | boolean | — | false (only root directories are cached; existing behavior) | Optional and experimental: additionally cache every subdirectory by its own `Directory` digest, not just the root directory. REAPI Merkle nodes are content-addressed, so a subtree that is byte-identical between two different roots has the same digest and can be materialized with a single hardlink pass instead of being rebuilt from the CAS. This makes the common "one input file changed out of thousands" case reuse every unchanged subtree. | +| `max_concurrent_fetches` | integer (uint) | — | 64 | Maximum number of concurrent slow-store fetches across ALL directory constructions of this cache. This bound protects backing stores from RPC storms: per-level construction concurrency compounds multiplicatively across tree levels and concurrent actions. | + +## PropertyType + +When the scheduler matches tasks to workers that are capable of running +the task, this value will be used to determine how the property is treated. + +One of: + +- string +- `"minimum"` — Requires the platform property to be a u64 and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that has less than this value. +- `"exact"` — Requires the platform property to be a string and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that does not have this property set to the value with exact string match. +- `"priority"` — Does not restrict on this value and instead will be passed to the worker as an informational piece. In the future this will be used by the scheduler and worker to cause the scheduler to prefer certain workers over others, but not restrict them based on these values. + +## WorkerAllocationStrategy + +When a worker is being searched for to run a job, this will be used +on how to choose which worker should run the job when multiple +workers are able to run the task. + +| Value | Description | +| --- | --- | +| `"least_recently_used"` | Prefer workers that have been least recently used to run a job. | +| `"most_recently_used"` | Prefer workers that have been most recently used to run a job. | + +## ExperimentalSimpleSchedulerBackend + +One of: + +- `"memory"` — Use an in-memory store for the scheduler. +- `redis`: [ExperimentalRedisSchedulerBackend](#experimentalredisschedulerbackend) — Use a Redis store for the scheduler. + +## SchedulerSpec + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## PropertyModification + +Plus exactly one of the following variants (the key selects the variant): + +### `add` + +Add a property to the action properties. + +**Type:** [PlatformPropertyAddition](#platformpropertyaddition) + +### `remove` + +Remove a named property from the action. + +**Type:** string + +### `replace` + +If a property is found, then replace it with another one. + +**Type:** [PlatformPropertyReplacement](#platformpropertyreplacement) + +## HttpListener + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `socket_address` | string | Yes | — | Address to listen on. Example: `127.0.0.1:8080` or `:8080` to listen to all IPs. | +| `freebind` | boolean | — | false | Allow binding `socket_address` before it is assigned locally. | +| `compression` | [HttpCompressionConfig](#httpcompressionconfig) | — | — | Data transport compression configuration to use for this service. | +| `advanced_http` | [HttpServerConfig](#httpserverconfig) | — | — | Advanced HTTP server configuration. | +| `max_decoding_message_size` | integer (uint) | — | 4 MiB | Maximum number of bytes to decode on each grpc stream chunk. | +| `tls` | [TlsConfig](#tlsconfig) | — | — | TLS configuration for this server. If not set, the server will not use TLS. | + +## CasServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `experimental_chunking` | [CasChunkingConfig](#caschunkingconfig) | — | not set — chunking RPCs are rejected, nothing is advertised, | Optional and experimental: enables the REAPI `SplitBlob`/`SpliceBlob` RPCs used by content-defined chunking clients (e.g. Bazel's `--experimental_remote_cache_chunking`). When set, the capabilities service advertises blob split/splice support and `FastCDC` 2020 parameters for this instance. When `cas_store` is a grpc store the RPCs are forwarded to the backend (which must support chunking with matching parameters); otherwise they are served locally. | + +## ActionCacheServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `ac_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## CapabilitiesServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | +| `remote_cache_compression` | boolean | — | — | Whether this instance supports Bazel remote cache compression. When enabled, the capabilities service advertises zstd wire compression and the ByteStream/CAS services accept REAPI compressed-blobs/zstd data. | + +## ExecutionServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. This value must be a CAS store reference. | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## ByteStreamServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | Name of the store in the "stores" configuration. | +| `max_bytes_per_stream` | integer (uint) | — | 64KiB | Max number of bytes to send on each grpc stream chunk. According to [https://github.com/grpc/grpc.github.io/issues/371](https://github.com/grpc/grpc.github.io/issues/371) 16KiB - 64KiB is optimal. | +| `persist_stream_on_disconnect_timeout_s` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | + +## FetchServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `fetch_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## PushServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `push_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## WorkerApiConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## BepConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish build events to. The store name referenced in the `stores` map in the main config. | + +## AdminConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/admin" | Path to register the admin API. If path is "/admin", and your domain is "example.com", you can reach the endpoint with: [http://example.com/admin](http://example.com/admin). | + +## HealthConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/status" | Path to register the health status check. If path is "/status", and your domain is "example.com", you can reach the endpoint with: [http://example.com/status](http://example.com/status). | +| `timeout_seconds` | integer (uint64) | — | 5s | Timeout on health checks. | + +## ErrorCode + +The possible error codes that might occur on an upstream request. + +| Value | Description | +| --- | --- | +| `"Cancelled"` | | +| `"Unknown"` | | +| `"InvalidArgument"` | | +| `"DeadlineExceeded"` | | +| `"NotFound"` | | +| `"AlreadyExists"` | | +| `"PermissionDenied"` | | +| `"ResourceExhausted"` | | +| `"FailedPrecondition"` | | +| `"Aborted"` | | +| `"OutOfRange"` | | +| `"Unimplemented"` | | +| `"Internal"` | | +| `"Unavailable"` | | +| `"DataLoss"` | | +| `"Unauthenticated"` | | + +## Lz4Config + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `block_size` | integer (uint32) | — | 65536 (64k) | Size of the blocks to compress. Higher values require more ram, but might yield slightly better compression ratios. | +| `max_decode_block_size` | integer (uint32) | — | value in `block_size` | Maximum size allowed to attempt to deserialize data into. This is needed because the `block_size` is embedded into the data so if there was a bad actor, they could upload an extremely large `block_size`'ed entry and we'd allocate a large amount of memory when retrieving the data. To prevent this from happening, we allow you to specify the maximum that we'll attempt to deserialize. | + +## ClientTlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ca_file` | string | — | — | Path to the certificate authority to use to validate the remote. | +| `cert_file` | string | — | — | Path to the certificate file for client authentication. | +| `key_file` | string | — | — | Path to the private key file for client authentication. | +| `use_native_roots` | boolean | — | false | If set the client will use the native roots for TLS connections. | + +## UploadCacheResultsStrategy + +| Value | Description | +| --- | --- | +| `"success_only"` | Only upload action results with an exit code of 0. | +| `"never"` | Don't upload any action results. | +| `"everything"` | Upload all action results that complete. | +| `"failures_only"` | Only upload action results that fail. | + +## ExperimentalRedisSchedulerBackend + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `redis_store` | string | Yes | — | A reference to the Redis store to use for the scheduler. Note: This MUST resolve to a `RedisSpec`. | + +## PlatformPropertyAddition + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to add. | +| `value` | string | Yes | — | The value to assign to the property. | + +## PlatformPropertyReplacement + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to replace. | +| `value` | string | — | — | The value to match against, if unset then any instance matches. | +| `new_name` | string | Yes | — | The new name of the property. | +| `new_value` | string | — | — | The value to assign to the property, if unset will remain the same. | + +## HttpCompressionConfig + +Note: Compressing data in the cloud rarely has a benefit, since most +cloud providers have very high bandwidth backplanes. However, for +clients not inside the data center, it might be a good idea to +compress data to and from the cloud. This will however come at a high +CPU and performance cost. If you are making remote execution share the +same CAS/AC servers as client's remote cache, you can create multiple +services with different compression settings that are served on +different ports. Then configure the non-cloud clients to use one port +and cloud-clients to use another. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `send_compression_algorithm` | [HttpCompressionAlgorithm](#httpcompressionalgorithm) | — | `HttpCompressionAlgorithm::None` | The compression algorithm that the server will use when sending responses to clients. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | +| `accepted_compression_algorithms` | array of [HttpCompressionAlgorithm](#httpcompressionalgorithm) | Yes | {no supported compression} | The compression algorithm that the server will accept from clients. The server will broadcast the supported compression algorithms to clients and the client will choose which compression algorithm to use. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | + +## HttpServerConfig + +Advanced HTTP configuration. These generally should not be set. +For documentation on these settings, see the hyper documentation: +See: [hyper HTTP server docs](https://docs.rs/hyper/latest/hyper/server/conn/struct.Http.html) + +Note: All of these default to the default values from hyper unless otherwise +specified. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `http2_keep_alive_interval` | integer (uint32) | — | — | Interval to send keep-alive pings via HTTP2. Note: This is in seconds. | +| `experimental_http2_max_pending_accept_reset_streams` | integer (uint32) | — | — | | +| `experimental_http2_initial_stream_window_size` | integer (uint32) | — | — | | +| `experimental_http2_initial_connection_window_size` | integer (uint32) | — | — | | +| `experimental_http2_adaptive_window` | boolean | — | — | | +| `experimental_http2_max_frame_size` | integer (uint32) | — | — | | +| `experimental_http2_max_concurrent_streams` | integer (uint32) | — | — | | +| `experimental_http2_keep_alive_timeout_s` | integer (uint32) | — | — | | +| `experimental_http2_max_send_buf_size` | integer (uint32) | — | — | | +| `experimental_http2_enable_connect_protocol` | boolean | — | — | | +| `experimental_http2_max_header_list_size` | integer (uint32) | — | — | | + +## TlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cert_file` | string | Yes | — | Path to the certificate file. | +| `key_file` | string | Yes | — | Path to the private key file. | +| `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | +| `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | + +## CasChunkingConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | string | — | — | The store name referenced in the `stores` map in the main config used to persist blob-to-chunks layouts. Keys are the digests of the original blobs and values are serialized chunk layouts (which do not hash to those digests), so this store MUST NOT perform content digest verification and MUST NOT be the same store as `cas_store` — writing layouts into the CAS would overwrite blob content. Using the same store name as `cas_store` is rejected at startup. | +| `avg_chunk_size_bytes` | integer (uint64) | — | 524288 (512 KiB) | The average chunk size in bytes advertised to clients through the `FastCDC` 2020 capability parameters and used for server-side chunking in `SplitBlob`. Clients derive the minimum and maximum chunk sizes from this value (avg / 4 and avg * 4). The value must be between 1 KiB and 1 MiB. | +| `max_chunk_count` | integer (uint64) | — | 50000 | Maximum number of chunks accepted in a `SpliceBlob` request or produced by on-demand chunking in `SplitBlob`. Blobs that would produce more chunks are served without chunking (`SplitBlob` returns `NOT_FOUND` and clients fall back to a regular download). This bounds the size of stored chunk layouts and of `SplitBlobResponse` messages (roughly 80-140 bytes per chunk). At the default average chunk size the default cap supports blobs up to ~25 GiB; note that values above ~50000 may produce responses that exceed default gRPC message size limits on clients. | + +## CapabilitiesRemoteExecutionConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | Scheduler used to configure the capabilities of remote execution. | + +## HttpCompressionAlgorithm + +| Value | Description | +| --- | --- | +| `"none"` | No compression. | +| `"gzip"` | Zlib compression. | + +## Reading the source + +If anything here disagrees with the binary, the source wins: + +- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.2/nativelink-config/src/stores.rs) +- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.2/nativelink-config/src/cas_server.rs) +- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.2/nativelink-config/src/schedulers.rs) diff --git a/web/apps/docs/content/docs/reference/nativelink-config/v1.6.3.mdx b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.3.mdx new file mode 100644 index 000000000..e77a47e3a --- /dev/null +++ b/web/apps/docs/content/docs/reference/nativelink-config/v1.6.3.mdx @@ -0,0 +1,1545 @@ +--- +title: Configuration reference +description: Every knob in the NativeLink JSON5 configuration — types, defaults, and links to source, autogenerated from the Rust config crate. +full: true +--- + +{/* AUTOGENERATED — do not edit by hand. + Source: nativelink-config @ v1.6.3 (46c3d0fa) + Regenerate from web/: bun --filter @nativelink/docs gen:config-reference */} + + + +This is the canonical NativeLink configuration reference for **v1.6.3**. +It is autogenerated from the Rust config crate +([`nativelink-config/src`](https://github.com/TraceMachina/nativelink/tree/v1.6.3/nativelink-config/src)) via the `build-schema` binary, so +it can never drift from what the binary actually deserializes. + +## Top-level fields + +The root object (`CasConfig`) accepts the following fields: + +| Field | Type | Required | Description | +| --- | --- | --- | --- | +| `stores` | array of [NamedStoreConfig](#namedstoreconfig) | Yes | List of stores available to use in this config. The keys can be used in other configs when needing to reference a store. | +| `workers` | array of [WorkerConfig](#workerconfig) | — | Worker configurations used to execute jobs. | +| `schedulers` | array of [NamedSchedulerConfig](#namedschedulerconfig) | — | List of schedulers available to use in this config. The keys can be used in other configs when needing to reference a scheduler. | +| `servers` | array of [ServerConfig](#serverconfig) | Yes | Servers to setup for this process. | +| `experimental_origin_events` | [OriginEventsSpec](#origineventsspec) | — | Experimental - Origin events configuration. This is the service that will collect and publish nativelink events to a store for processing by an external service. | +| `global` | [GlobalConfig](#globalconfig) | — | Any global configurations that apply to all modules live here. | + +## Configuration types + +Every type reachable from the root configuration, in reading order. + +## NamedStoreConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `cache_metrics` + +Cache metrics store wraps another store and emits low-cardinality +OpenTelemetry cache operation metrics for the wrapped store. + +This wrapper is opt-in. Stores that are not explicitly wrapped by +`cache_metrics` are constructed exactly as they are without this +wrapper and do not pay its hot-path timing or recording cost. + +**Example JSON5 config:** +```json5 +"cache_metrics": { + "cache_type": "cas", + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-cas", + "temp_path": "~/.cache/nativelink/tmp_path-cas" + } + } +} +``` + +**Type:** [CacheMetricsSpec](#cachemetricsspec) + +### `memory` + +Memory store will store all data in a hash map in memory. + +**Example JSON5 config:** +```json5 +"memory": { + "eviction_policy": { + "max_bytes": "10mb", + } +} +``` + +**Type:** [MemorySpec](#memoryspec) + +### `experimental_cloud_object_store` + +A generic blob store that will store files on the cloud +provider. This configuration will never delete files, so you are +responsible for purging old files in other ways. +It supports the following backends: + +1. **Amazon S3:** + S3 store will use Amazon's S3 service as a backend to store + the files. This configuration can be used to share files + across multiple instances. Uses system certificates for TLS + verification via `rustls-platform-verifier`. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "aws", + "region": "eu-north-1", + "bucket": "crossplane-bucket-af79aeca9", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +2. **Google Cloud Storage:** + GCS store uses Google's GCS service as a backend to store + the files. This configuration can be used to share files + across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "gcs", + "bucket": "test-bucket", + "key_prefix": "test-prefix-index/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +3. **Azure Blob Store:** + Azure Blob store will use Microsoft's Azure Blob service as a + backend to store the files. This configuration can be used to + share files across multiple instances. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "azure", + "account_name": "cloudshell1393657559", + "container": "simple-test-container", + "key_prefix": "folder/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +4. **NetApp ONTAP S3:** + NetApp ONTAP S3 store will use ONTAP's S3-compatible storage as a backend + to store files. This store is specifically configured for ONTAP's S3 requirements + including custom TLS configuration, credentials management, and proper vserver + configuration. + + This store uses AWS environment variables for credentials: + - `AWS_ACCESS_KEY_ID` + - `AWS_SECRET_ACCESS_KEY` + - `AWS_DEFAULT_REGION` + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "ontap", + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "root_certificates": "/path/to/certs.pem", // Optional + "key_prefix": "test-prefix/", // Optional + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +5. **Cloudflare R2:** + R2 store uses Cloudflare's R2 service as a backend. R2 speaks the + S3 API, so this is a thin wrapper that derives the account-scoped + endpoint (`https://{account_id}.r2.cloudflarestorage.com`) for you. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "r2", + "account_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + "bucket": "nativelink-cas", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + }, + "multipart_max_concurrent_uploads": 10 + } + ``` + +6. **Oracle Cloud Infrastructure (OCI) Object Storage:** + OCI store uses Oracle Cloud Infrastructure's S3-compatible Object + Storage API. The path-style endpoint is derived from your Object + Storage `namespace` and `region` as + `https://{namespace}.compat.objectstorage.{region}.oci.customer-oci.com`. + Authenticate with a Customer Secret Key (Access Key/Secret Key pair + created under User Settings -> Customer secret keys in the OCI + console); the secret cannot be retrieved after generation, so read + it from an env var via shellexpand. + + **Example JSON5 config:** + ```json5 + "experimental_cloud_object_store": { + "provider": "oci", + "namespace": "your-object-storage-namespace", + "region": "us-phoenix-1", + "bucket": "nativelink-cas", + "access_key_id": "oci_access_key_id", + "secret_access_key": "oci_secret_access_key", + "key_prefix": "test-prefix/", + "retry": { + "max_retries": 6, + "delay": 0.3, + "jitter": 0.5 + } + } + ``` + +**Type:** [ExperimentalCloudObjectSpec](#experimentalcloudobjectspec) + +### `ontap_s3_existence_cache` + +ONTAP S3 Existence Cache provides a caching layer on top of the ONTAP S3 store +to optimize repeated existence checks. It maintains an in-memory cache of object +digests and periodically syncs this cache to disk for persistence. + +The cache helps reduce latency for repeated calls to check object existence, +while still ensuring eventual consistency with the underlying ONTAP S3 store. + +Example JSON5 config: +```json5 +"ontap_s3_existence_cache": { + "index_path": "/path/to/cache/index.json", + "sync_interval_seconds": 300, + "backend": { + "endpoint": "https://ontap-s3-endpoint:443", + "vserver_name": "your-vserver", + "bucket": "your-bucket", + "key_prefix": "test-prefix/" + } +} +``` + +**Type:** [OntapS3ExistenceCacheSpec](#ontaps3existencecachespec) + +### `verify` + +Verify store is used to apply verifications to an underlying +store implementation. It is strongly encouraged to validate +as much data as you can before accepting data from a client, +failing to do so may cause the data in the store to be +populated with invalid data causing all kinds of problems. + +The suggested configuration is to have the CAS validate the +hash and size and the AC validate nothing. + +**Example JSON5 config:** +```json5 +"verify": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb" + } + }, + }, + "verify_size": true, + "verify_hash": true +} +``` + +**Type:** [VerifySpec](#verifyspec) + +### `completeness_checking` + +Completeness checking store verifies if the +output files & folders exist in the CAS before forwarding +the request to the underlying store. +Note: This store should only be used on AC stores. + +**Example JSON5 config:** +```json5 +"completeness_checking": { + "backend": { + "filesystem": { + "content_path": "~/.cache/nativelink/content_path-ac", + "temp_path": "~/.cache/nativelink/tmp_path-ac", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "cas_store": { + "ref_store": { + "name": "CAS_MAIN_STORE" + } + } +} +``` + +**Type:** [CompletenessCheckingSpec](#completenesscheckingspec) + +### `compression` + +A compression store that will compress the data inbound and +outbound. There will be a non-trivial cost to compress and +decompress the data, but in many cases if the final store is +a store that requires network transport and/or storage space +is a concern it is often faster and more efficient to use this +store before those stores. + +**Example JSON5 config:** +```json5 +"compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-cas", + "temp_path": "/tmp/nativelink/data/tmp_path-cas", + "eviction_policy": { + "max_bytes": "2gb", + } + } + } +} +``` + +**Type:** [CompressionSpec](#compressionspec) + +### `dedup` + +A dedup store will take the inputs and run a rolling hash +algorithm on them to slice the input into smaller parts then +run a sha256 algorithm on the slice and if the object doesn't +already exist, upload the slice to the `content_store` using +a new digest of just the slice. Once all parts exist, an +Action-Cache-like digest will be built and uploaded to the +`index_store` which will contain a reference to each +chunk/digest of the uploaded file. Downloading a request will +first grab the index from the `index_store`, and forward the +download content of each chunk as if it were one file. + +This store is exceptionally good when the following conditions +are met: +* Content is mostly the same (inserts, updates, deletes are ok) +* Content is not compressed or encrypted +* Uploading or downloading from `content_store` is the bottleneck. + +Note: This store pairs well when used with `CompressionSpec` as +the `content_store`, but never put `DedupSpec` as the backend of +`CompressionSpec` as it will negate all the gains. + +Note: When running `.has()` on this store, it will only check +to see if the entry exists in the `index_store` and not check +if the individual chunks exist in the `content_store`. + +**Example JSON5 config:** +```json5 +"dedup": { + "index_store": { + "memory": { + "eviction_policy": { + "max_bytes": "1GB", + } + } + }, + "content_store": { + "compression": { + "compression_algorithm": { + "lz4": {} + }, + "backend": { + "fast_slow": { + "fast": { + "memory": { + "eviction_policy": { + "max_bytes": "500MB", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-content", + "temp_path": "/tmp/nativelink/data/tmp_path-content", + "eviction_policy": { + "max_bytes": "2gb" + } + } + } + } + } + } + } +} +``` + +**Type:** [DedupSpec](#dedupspec) + +### `existence_cache` + +Existence store will wrap around another store and cache calls +to has so that subsequent `has_with_results` calls will be +faster. This is useful for cases when you have a store that +is slow to respond to has calls. +Note: This store should only be used on CAS stores. + +**Example JSON5 config:** +```json5 +"existence_cache": { + "backend": { + "memory": { + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + // Note this is the existence store policy, not the backend policy + "eviction_policy": { + "max_seconds": 100, + } +} +``` + +**Type:** [ExistenceCacheSpec](#existencecachespec) + +### `fast_slow` + +`FastSlow` store will first try to fetch the data from the `fast` +store and then if it does not exist try the `slow` store. +When the object does exist in the `slow` store, it will copy +the data to the `fast` store while returning the data. +This store should be thought of as a store that "buffers" +the data to the `fast` store. +On uploads it will mirror data to both `fast` and `slow` stores. + +WARNING: If you need data to always exist in the `slow` store +for something like remote execution, be careful because this +store will never check to see if the objects exist in the +`slow` store if it exists in the `fast` store (i.e. it assumes +that if an object exists in the `fast` store it will exist in +the `slow` store). + +***Example JSON5 config:*** +```json5 +"fast_slow": { + "fast": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + }, + "slow": { + "filesystem": { + "content_path": "/tmp/nativelink/data/content_path-index", + "temp_path": "/tmp/nativelink/data/tmp_path-index", + "eviction_policy": { + "max_bytes": "500mb", + } + } + } +} +``` + +**Type:** [FastSlowSpec](#fastslowspec) + +### `shard` + +Shards the data to multiple stores. This is useful for cases +when you want to distribute the load across multiple stores. +The digest hash is used to determine which store to send the +data to. + +**Example JSON5 config:** +```json5 +"shard": { + "stores": [ + { + "store": { + "memory": { + "eviction_policy": { + "max_bytes": "10mb" + }, + }, + }, + "weight": 1 + }] +} +``` + +**Type:** [ShardSpec](#shardspec) + +### `filesystem` + +Stores the data on the filesystem. This store is designed for +local persistent storage. Restarts of this program should restore +the previous state, meaning anything uploaded will be persistent +as long as the filesystem integrity holds. + +**Example JSON5 config:** +```json5 +"filesystem": { + "content_path": "/tmp/nativelink/data-worker-test/content_path-cas", + "temp_path": "/tmp/nativelink/data-worker-test/tmp_path-cas", + "eviction_policy": { + "max_bytes": "10gb", + } +} +``` + +**Type:** [FilesystemSpec](#filesystemspec) + +### `ref_store` + +Store used to reference a store in the root store manager. +This is useful for cases when you want to share a store in different +nested stores. Example, you may want to share the same memory store +used for the action cache, but use a `FastSlowSpec` and have the fast +store also share the memory store for efficiency. + +**Example JSON5 config:** +```json5 +"ref_store": { + "name": "FS_CONTENT_STORE" +} +``` + +**Type:** [RefSpec](#refspec) + +### `size_partitioning` + +Uses the size field of the digest to separate which store to send the +data. This is useful for cases when you'd like to put small objects +in one store and large objects in another store. This should only be +used if the size field is the real size of the content, in other +words, don't use on AC (Action Cache) stores. Any store where you can +safely use `VerifySpec.verify_size = true`, this store should be safe +to use (i.e. CAS stores). + +**Example JSON5 config:** +```json5 +"size_partitioning": { + "size": "128mib", + "lower_store": { + "memory": { + "eviction_policy": { + "max_bytes": "${NATIVELINK_CAS_MEMORY_CONTENT_LIMIT:-100mb}" + } + } + }, + "upper_store": { + /// This store discards data larger than 128mib. + "noop": {} + } +} +``` + +**Type:** [SizePartitioningSpec](#sizepartitioningspec) + +### `grpc` + +This store will pass-through calls to another gRPC store. This store +is not designed to be used as a sub-store of another store, but it +does satisfy the interface and will likely work. + +One major GOTCHA is that some stores use a special function on this +store to get the size of the underlying object, which is only reliable +when this store is serving the a CAS store, not an AC store. If using +this store directly without being a child of any store there are no +side effects and is the most efficient way to use it. + +**Example JSON5 config:** +```json5 +"grpc": { + "instance_name": "main", + "endpoints": [ + {"address": "grpc://${CAS_ENDPOINT:-127.0.0.1}:50051"} + ], + "connections_per_endpoint": "5", + "rpc_timeout_s": "5m", + "store_type": "ac", + // Static headers attached to every outgoing request to the upstream + // remote cache. Useful for fixed service-account credentials. + "headers": { + "authorization": "Bearer my-static-token" + }, + // Header names to copy from the inbound client request and forward to + // the upstream remote cache. Use this to pass through dynamic + // credentials such as a JWT sent by the build client. + "forward_headers": ["authorization", "x-custom-token"] +} +``` + +**Type:** [GrpcSpec](#grpcspec) + +### `redis_store` + +Stores data in any stores compatible with Redis APIs. + +Pairs well with `SizePartitioning` and/or `FastSlow` stores. +Ideal for accepting small object sizes as most Redis store +services have a max file upload of between 256Mb-512Mb. + +If you are using Redis together with any stores above it +e.g. existence cache, you will need to configure `notify-keyspace-events` +to `KA` as per [https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/#configuration](https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/#configuration) +in order for us to get eviction events. Failing to do so will get you +log messages complaining about it, as well as errors like [https://github.com/TraceMachina/nativelink/issues/2436](https://github.com/TraceMachina/nativelink/issues/2436) + +**Example JSON5 config:** +```json5 +"redis_store": { + "addresses": [ + "redis://127.0.0.1:6379/", + ], + "max_client_permits": 1000, +} +``` + +**Type:** [RedisSpec](#redisspec) + +### `noop` + +Noop store is a store that sends streams into the void and all data +retrieval will return 404 (`NotFound`). This can be useful for cases +where you may need to partition your data and part of your data needs +to be discarded. + +**Example JSON5 config:** +```json5 +"noop": {} +``` + +**Type:** [NoopSpec](#noopspec) + +### `experimental_mongo` + +Experimental `MongoDB` store implementation. + +This store uses `MongoDB` as a backend for storing data. It supports +both CAS (Content Addressable Storage) and scheduler data with +optional change streams for real-time updates. + +**Example JSON5 config:** +```json5 +"experimental_mongo": { + "connection_string": "mongodb://localhost:27017", + "database": "nativelink", + "cas_collection": "cas", + "key_prefix": "cas:", + "read_chunk_size": 65536, + "max_concurrent_uploads": 10, + "enable_change_streams": false, + "max_requests": "100" +} +``` + +**Type:** [ExperimentalMongoSpec](#experimentalmongospec) + +## WorkerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `local` + +A worker type that executes jobs locally on this machine. + +**Type:** [LocalWorkerConfig](#localworkerconfig) + +## NamedSchedulerConfig + +**Common fields** + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | | + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## ServerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {index of server in config} | Name of the server. This is used to help identify the service for telemetry and logs. | +| `listener` | [ListenerConfig](#listenerconfig) | Yes | — | Configuration | +| `services` | [ServicesConfig](#servicesconfig) | — | — | Services to attach to server. | +| `experimental_identity_header` | [IdentityHeaderSpec](#identityheaderspec) | — | {see `IdentityHeaderSpec`} | The config related to identifying the client. | + +## OriginEventsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `publisher` | [OriginEventsPublisherSpec](#origineventspublisherspec) | Yes | — | The publisher configuration for origin events. | +| `max_event_queue_size` | integer (uint) | — | 65536 (zero defaults to this) | The maximum number of events to queue before applying back pressure. IMPORTANT: Backpressure causes all clients to slow down significantly. Zero is default. | + +## GlobalConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_open_files` | integer (uint) | Yes | 24576 (= 24 * 1024) | Maximum number of open files that can be opened at one time. This value is not strictly enforced, it is a best effort. Some internal libraries open files or read metadata from a files which do not obey this limit, however the vast majority of cases will have this limit be honored. This value must be larger than `ulimit -n` to have any effect. Any network open file descriptors is not counted in this limit, but is counted in the kernel limit. It is a good idea to set a very large `ulimit -n`. Note: This value must be greater than 10. | +| `default_digest_hash_function` | [ConfigDigestHashFunction](#configdigesthashfunction) | — | `ConfigDigestHashFunction::sha256` | Default hash function to use while uploading blobs to the CAS when not set by client. | +| `default_digest_size_health_check` | integer (uint) | — | 1024*1024 (1MiB) | Default digest size to use for health check when running diagnostics checks. Health checks are expected to use this size for filling a buffer that is used for creation of digest. | + +## CacheMetricsSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cache_type` | string | Yes | — | Low-cardinality cache type label for metrics, for example `cas` or `ac`. | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to wrap with cache operation metrics. | + +## MemorySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## ExperimentalCloudObjectSpec + +See [`experimental_cloud_object_store`](#experimental_cloud_object_store-1) for details + +## OntapS3ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_path` | string | Yes | — | | +| `sync_interval_seconds` | integer (uint32) | Yes | — | | +| `backend` | [ExperimentalOntapS3Spec](#experimentalontaps3spec) | Yes | — | | + +## VerifySpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `verify_size` | boolean | — | `false` | If set the store will verify the size of the data before accepting an upload of data. | +| `verify_hash` | boolean | — | `false` | If the data should be hashed and verify that the key matches the computed hash. The hash function is automatically determined based request and if not set will use the global default. | + +## CompletenessCheckingSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store that will have it's results validated before sending to client. | +| `cas_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | When a request is made, the results are decoded and all output digests/files are verified to exist in this CAS store before returning success. | + +## CompressionSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `compression_algorithm` | [CompressionAlgorithm](#compressionalgorithm) | Yes | — | The compression algorithm to use. | + +## DedupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store used to store the index of each dedup slice. This store should generally be fast and small. | +| `content_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The store where the individual chunks will be uploaded. This store should generally be the slower & larger store. | +| `min_size` | integer (uint32) | — | 64k | Minimum size that a chunk will be when slicing up the content. Note: This setting can be increased to improve performance because it will actually not check this number of bytes when deciding where to partition the data. | +| `normal_size` | integer (uint32) | — | 256k | A best-effort attempt will be made to keep the average size of the chunks to this number. It is not a guarantee, but a slight attempt will be made. | +| `max_size` | integer (uint32) | — | 512k | Maximum size a chunk is allowed to be. | +| `max_concurrent_fetch_per_get` | integer (uint32) | — | 10 | Due to implementation detail, we want to prefer to download the first chunks of the file so we can stream the content out and free up some of our buffers. This configuration will be used to restrict the number of concurrent chunk downloads at a time per `get()` request. | + +## ExistenceCacheSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `backend` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | The underlying store wrap around. All content will first flow through self before forwarding to backend. In the event there is an error detected in self, the connection to the backend will be terminated, and early termination should always cause updates to fail on the backend. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | + +## FastSlowSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `fast` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Fast store that will be attempted to be contacted before reaching out to the `slow` store. | +| `fast_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the fast store. This can be useful to set to Get for worker nodes such that results are persisted to the slow store only. | +| `slow` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | If the object does not exist in the `fast` store it will try to get it from this store. | +| `slow_direction` | [StoreDirection](#storedirection) | — | `"both"` | How to handle the slow store. This can be useful if creating a diode and you wish to have an upstream read only store. | +| `bypass_dedup_threshold_bytes` | integer (uint64) | — | disabled (0) | Reads of blobs at or above this size skip the leader/follower dedup map and stream straight from the slow store without populating the fast tier. `0` (the default) disables the bypass: every read goes through dedup, matching the prior behaviour. Enable it by setting a threshold — 256 MiB is a reasonable starting point for backends where large-blob dedup is a net loss (followers tend to time out anyway), but the right value is workload-dependent. | + +## ShardSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `stores` | array of [ShardConfig](#shardconfig) | Yes | — | Stores to shard the data to. | + +## FilesystemSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `content_path` | string | Yes | — | Path on the system where to store the actual content. This is where the bulk of the data will be placed. On service boot this folder will be scanned and all files will be added to the cache. In the event one of the files doesn't match the criteria, the file will be deleted. | +| `temp_path` | string | Yes | — | A temporary location of where files that are being uploaded or deleted will be placed while the content cannot be guaranteed to be accurate. This location must be on the same block device as `content_path` so atomic moves can happen (i.e. move without copy). All files in this folder will be deleted on every startup. | +| `read_buffer_size` | integer (uint32) | — | 32k | Buffer size to use when reading files. Generally this should be left to the default value except for testing. | +| `eviction_policy` | [EvictionPolicy](#evictionpolicy) | — | — | Policy used to evict items out of the store. Failure to set this value will cause items to never be removed from the store causing infinite memory usage. | +| `block_size` | integer (uint64) | — | 4kb | The block size of the filesystem for the running machine value is used to determine an entry's actual size on disk consumed For a 4KB block size filesystem, a 1B file actually consumes 4KB | +| `max_concurrent_writes` | integer (uint) | — | unlimited | Maximum number of concurrent write operations allowed. Each write involves streaming data to a temp file and calling `sync_all()`, which can saturate disk I/O when many writes happen simultaneously. Limiting concurrency prevents disk saturation from blocking the async runtime. A value of 0 means unlimited (no concurrency limit). | +| `evict_page_cache` | boolean | — | false | When true, advise the kernel to drop the page cache for each blob after it is written or read (`posix_fadvise` with `POSIX_FADV_DONTNEED`). On real filesystems this takes a globally serialized, all-CPU kernel path that stalls on many-core hosts, and it evicts the page-cache tier that fast-disk deployments rely on. Leave off unless you specifically want to keep this store's I/O out of the page cache. | + +## RefSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | Name of the store under the root "stores" config object. | + +## SizePartitioningSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `size` | integer (uint64) | Yes | — | Size to partition the data on. | +| `lower_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is < (less than) size. | +| `upper_store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to send data when object is >= (less than eq) size. | + +## GrpcSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Instance name for gRPC calls. Proxy calls will have the `instance_name` changed to this. | +| `endpoints` | array of [GrpcEndpoint](#grpcendpoint) | Yes | — | The endpoint of the grpc connection. | +| `store_type` | [StoreType](#storetype) | Yes | — | The type of the upstream store, this ensures that the correct server calls are made. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | `0` | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | +| `rpc_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) allowed for a single RPC request (e.g. a `ByteStream.Write` call) before it is cancelled. | +| `use_legacy_resource_names` | boolean | — | false | Use legacy `ByteStream` resource name format, omitting the digest function component from the path. | +| `headers` | map of string to string | — | — | Static headers to attach to every outgoing gRPC request sent to this store's upstream endpoints. Useful for fixed authentication tokens (e.g. `{"authorization": "Bearer "}`) and other static metadata. | +| `forward_headers` | array of string | — | — | Header names to forward from the incoming client request to every outgoing upstream request. The header value is taken from the client request that triggered this store operation. Use this to pass through dynamic credentials such as JWT tokens sent by build clients. | +| `experimental_read_batching` | [GrpcReadBatchingConfig](#grpcreadbatchingconfig) | — | unset (disabled) | Optional and experimental: coalesce small-blob reads into `BatchReadBlobs` RPCs instead of issuing one `ByteStream` `Read` stream per blob. Each `ByteStream` read carries a fixed per-RPC cost, so batching many small reads into a single `BatchReadBlobs` request can dramatically reduce read latency for small blobs. | + +## RedisSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `addresses` | array of string | Yes | — | The hostname or IP address of the Redis server. Ex: `["redis://username:password@redis-server-url:6380/99"]` 99 Represents database ID, 6380 represents the port. | +| `response_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `command_timeout_ms` The response timeout for the Redis connection in seconds. | +| `connection_timeout_s` | integer (uint64) | — | 10 | DEPRECATED: use `connection_timeout_ms` | +| `experimental_pub_sub_channel` | string | — | (Empty String / No Channel) | An optional and experimental Redis channel to publish write events to. | +| `key_prefix` | string | — | (Empty String / No Prefix) | An optional prefix to prepend to all keys in this store. | +| `mode` | [RedisMode](#redismode) | — | standard, | Set the mode Redis is operating in. | +| `broadcast_channel_capacity` | integer (uint) | — | `0` | Deprecated as redis-rs doesn't use it | +| `command_timeout_ms` | integer (uint64) | — | 10000 (10 seconds) | The amount of time in milliseconds until the Redis store considers the command to be timed out. This will trigger a retry of the command and potentially a reconnection to the Redis server. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 (3 seconds) | The amount of time in milliseconds until the Redis store considers the connection to unresponsive. This will trigger a reconnection to the Redis server. | +| `health_check_timeout_ms` | integer (uint64) | — | 4000 (4 seconds) | Per-call ceiling for the `check_health` PING in milliseconds. | +| `read_chunk_size` | integer (uint) | — | 64KiB | The amount of data to read from the Redis server at a time. This is used to limit the amount of memory used when reading large objects from the Redis server as well as limiting the amount of time a single read operation can take. | +| `connection_pool_size` | integer (uint) | — | 3 | The number of connections to keep open to the Redis servers. | +| `max_chunk_uploads_per_update` | integer (uint) | — | 10 | The maximum number of upload chunks to allow per update. This is used to limit the amount of memory used when uploading large objects to the Redis server. A good rule of thumb is to think of the data as: `AVAIL_MEMORY / (read_chunk_size * max_chunk_uploads_per_update) = THORETICAL_MAX_CONCURRENT_UPLOADS` (note: it's a good idea to divide `AVAIL_MAX_MEMORY` by ~10 to account for other memory usage) | +| `scan_count` | integer (uint) | — | 10000 | The COUNT value passed when scanning keys in Redis. This is used to hint the amount of work that should be done per response. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_client_permits` | integer (uint) | — | 500 | Maximum number of permitted actions to the Redis store at any one time This stops problems with timeouts due to many, many inflight actions | +| `max_count_per_cursor` | integer (uint64) | — | 1500 | Maximum number of items returned per cursor for the search indexes May reduce thundering herd issues with worker provisioner at higher node counts, | + +## NoopSpec + +_No fields._ + +## ExperimentalMongoSpec + +Configuration for `ExperimentalMongoDB` store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `connection_string` | string | Yes | — | `ExperimentalMongoDB` connection string. Example: <mongodb://localhost:27017> or <mongodb+srv://cluster.mongodb.net> | +| `database` | string | — | "nativelink" | The database name to use. | +| `cas_collection` | string | — | "cas" | The collection name for CAS data. | +| `scheduler_collection` | string | — | "scheduler" | The collection name for scheduler data. | +| `key_prefix` | string | — | "" | Prefix to prepend to all keys stored in `MongoDB`. | +| `read_chunk_size` | integer (uint) | — | 65536 (64KB) | The maximum amount of data to read from `MongoDB` in a single chunk (in bytes). | +| `max_concurrent_uploads` | integer (uint) | — | 10 | Deprecated, unused Maximum number of concurrent uploads allowed. | +| `connection_timeout_ms` | integer (uint64) | — | 3000 | Connection timeout in milliseconds. | +| `command_timeout_ms` | integer (uint64) | — | 10000 | Command timeout in milliseconds. | +| `enable_change_streams` | boolean | — | false | Enable `MongoDB` change streams for real-time updates. Required for scheduler subscriptions. | +| `write_concern_w` | string | — | — | Write concern 'w' parameter. Can be a number (e.g., 1) or string (e.g., "majority"). | +| `write_concern_j` | boolean | — | — | Write concern 'j' parameter (journal acknowledgment). | +| `write_concern_timeout_ms` | integer (uint32) | — | — | Write concern timeout in milliseconds. | +| `max_requests` | integer (uint) | — | Unlimited | Limits the number of requests at any one time | + +## LocalWorkerConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | — | {Index position in the workers list} | Name of the worker. This is give a more friendly name to a worker for logging and metric publishing. This is also the prefix of the worker id (i.e. "{name}{uuidv6}"). | +| `worker_api_endpoint` | [EndpointConfig](#endpointconfig) | Yes | — | Endpoint which the worker will connect to the scheduler's `WorkerApiService`. | +| `max_action_timeout_s` | integer (uint) | — | 20 minutes | The maximum time an action is allowed to run. If a task requests for a timeout longer than this time limit, the task will be rejected. Value in seconds. | +| `max_upload_timeout_s` | integer (uint) | — | 10 minutes | Maximum time allowed for uploading action results to CAS after execution completes. If upload takes longer than this, the action fails with `DeadlineExceeded` and may be retried by the scheduler. Value in seconds. | +| `max_cleanup_wait_s` | integer (uint) | — | 30 seconds | Maximum time to wait for action directory cleanup before timing out. Value in seconds. | +| `max_cleanup_backoff_ms` | integer (uint) | — | 500 milliseconds | Maximum backoff duration for exponential backoff when waiting for cleanup. Value in milliseconds. | +| `max_inflight_tasks` | integer (uint64) | — | 0 (infinite tasks) | Maximum number of inflight tasks this worker can cope with. | +| `timeout_handled_externally` | boolean | — | false (`NativeLink` fully handles timeouts) | If timeout is handled in `entrypoint` or another wrapper script. If set to true `NativeLink` will not honor the timeout the action requested and instead will always force kill the action after `max_action_timeout` has been reached. If this is set to false, the smaller value of the action's timeout and `max_action_timeout` will be used to which `NativeLink` will kill the action. | +| `entrypoint` | string | — | {Use the command from the job request} | The command to execute on every execution request. This will be parsed as a command + arguments (not shell). Example: "run.sh" and a job with command: "sleep 5" will result in a command like: "run.sh sleep 5". | +| `experimental_precondition_script` | string | — | — | An optional script to run before every action is processed on the worker. The value should be the full path to the script to execute and will pause all actions on the worker if it returns an exit code other than 0. If not set, then the worker will never pause and will continue to accept jobs according to the scheduler configuration. This is useful, for example, if the worker should not take any more actions until there is enough resource available on the machine to handle them. | +| `cas_fast_slow_store` | string | Yes | — | Underlying CAS store that the worker will use to download CAS artifacts. This store must be a `FastSlowStore`. The `fast` store must be a `FileSystemStore` because it will use hardlinks when building out the files instead of copying the files. The slow store must eventually resolve to the same store the scheduler/client uses to send job requests. | +| `upload_action_result` | [UploadActionResultConfig](#uploadactionresultconfig) | — | — | Configuration for uploading action results. | +| `work_directory` | string | Yes | — | The directory work jobs will be executed from. This directory will be fully managed by the worker service and will be purged on startup. This directory and the directory referenced in `local_filesystem_store_ref`'s `stores::FilesystemStore::content_path` must be on the same filesystem. Hardlinks will be used when placing files that are accessible to the jobs that are sourced from `local_filesystem_store_ref`'s `content_path`. | +| `platform_properties` | map of string to [WorkerProperty](#workerproperty) | Yes | — | Properties of this worker. This configuration will be sent to the scheduler and used to tell the scheduler to restrict what should be executed on this worker. | +| `additional_environment` | map of string to [EnvironmentSource](#environmentsource) | — | — | An optional mapping of environment names to set for the execution as well as those specified in the action itself. If set, will set each key as an environment variable before executing the job with the value of the environment variable being the value of the property of the action being executed of that name or the fixed value. | +| `directory_cache` | [DirectoryCacheConfig](#directorycacheconfig) | — | — | Optional directory cache configuration for improving performance by caching reconstructed input directories and using hardlinks instead of rebuilding them from CAS for every action. | +| `use_namespaces` | boolean | — | False | Whether to use namespaces to isolate the execution. This is only available on Linux. It is highly recommended as it avoids a number of issues with zombie processes and also provides additional hermeticity. If explicitly set to true and it is not supported the worker will exit with an error. | +| `use_mount_namespace` | boolean | — | False | Whether to use a mount namespace to isolate the worker root. This is only available on Linux and when `use_namespaces` is true. It is highly recommended provides additional hermeticity. If explicitly set to true and it is not supported or `use_namespaces` is not set to true the worker will exit with an error. | + +## SimpleSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `supported_platform_properties` | map of string to [PropertyType](#propertytype) | — | — | A list of supported platform properties mapped to how these properties are used when the scheduler looks for worker nodes capable of running the task. | +| `retain_completed_for_s` | integer (uint32) | — | 60 seconds | The amount of time to retain completed actions for in case a `WaitExecution` is called after the action has completed. | +| `client_action_timeout_s` | integer (uint64) | — | 60 seconds | Mark operations as completed with error if no client has updated them within this duration. | +| `worker_timeout_s` | integer (uint64) | — | 5 seconds | Remove workers from pool once the worker has not responded in this amount of time in seconds. | +| `max_action_executing_timeout_s` | integer (uint64) | — | 0 (disabled) | Maximum time (seconds) an action can stay in Executing state without any worker update before being timed out and re-queued. This applies regardless of worker keepalive status, catching cases where a worker is alive (sending keepalives) but stuck on a specific action. Set to 0 to disable (relies only on `worker_timeout_s`). | +| `max_job_retries` | integer (uint) | — | 3 | If a job returns an internal error or times out this many times when attempting to run on a worker the scheduler will return the last error to the client. Jobs will be retried and this configuration is to help prevent one rogue job from infinitely retrying and taking up a lot of resources when the task itself is the one causing the server to go into a bad state. | +| `allocation_strategy` | [WorkerAllocationStrategy](#workerallocationstrategy) | — | `"least_recently_used"` | The strategy used to assign workers jobs. | +| `experimental_backend` | [ExperimentalSimpleSchedulerBackend](#experimentalsimpleschedulerbackend) | — | memory | The storage backend to use for the scheduler. | +| `worker_match_logging_interval_s` | integer (int64) | — | `10` | Every N seconds, do logging of worker matching e.g. "worker busy", "can't find any worker" Defaults to 10s. Can be set to `-1` to disable | +| `fallback_match_interval_s` | integer (int64) | — | `5` | Every N seconds, run a worker matching pass even if no task or worker change notification arrived. This is a safety net for missed notifications and for scheduler backends with eventually consistent searches (for example Redis), where an operation that was re-queued may not be visible to the search triggered by its own notification. Without this, such an operation can stay queued until an unrelated event triggers another matching pass. Defaults to 5s. Zero or any negative value disables it. | + +## SchedulerGrpcSpec + +A scheduler that forwards requests to an upstream scheduler. This +is useful to use when doing some kind of local action cache or CAS away from +the main cluster of workers. In general, it's more efficient to point the +build at the main scheduler directly though. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | [GrpcEndpoint](#grpcendpoint) | Yes | — | The upstream scheduler to forward requests to. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `max_concurrent_requests` | integer (uint) | — | unlimited | Limit the number of simultaneous upstream requests to this many. A value of zero is treated as unlimited. If the limit is reached the request is queued. | +| `connections_per_endpoint` | integer (uint) | — | 1 | The number of connections to make to each specified endpoint to balance the load over multiple TCP connections. | + +## CacheLookupSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | Yes | — | The reference to the action cache store used to return cached actions from rather than running them again. To prevent unintended issues, this store should probably be a `CompletenessCheckingSpec`. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use if cache lookup fails. | + +## PropertyModifierSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `modifications` | array of [PropertyModification](#propertymodification) | Yes | — | A list of modifications to perform to incoming actions for the nested scheduler. These are performed in order and blindly, so removing a property that doesn't exist is fine and overwriting an existing property is also fine. If adding properties that do not exist in the nested scheduler is not supported and will likely cause unexpected behaviour. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after modifying the properties. | + +## HistoricalResourceSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `hints_file` | string | Yes | — | JSON file containing historical resource hints keyed by Bazel `RequestMetadata` `target_id` and/or `action_mnemonic`. | +| `refresh_interval_s` | integer (uint64) | — | 30 seconds | Reload interval for `hints_file`. Set to 0 to load once. | +| `cpu_property_name` | string | — | `cpu_count` | Platform property name used for CPU minimum values. | +| `memory_property_name` | string | — | `memory_kb` | Platform property name used for memory minimum values, expressed in KiB. | +| `scheduler` | [SchedulerSpec](#schedulerspec) | Yes | — | The nested scheduler to use after applying resource hints. | + +## ListenerConfig + +Plus exactly one of the following variants (the key selects the variant): + +### `http` + +Listener for HTTP/HTTPS/HTTP2 sockets. + +**Type:** [HttpListener](#httplistener) + +## ServicesConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cas` | array of [CasServiceConfig](#casserviceconfig) | — | — | The Content Addressable Storage (CAS) backend config. The key is the `instance_name` used in the protocol and the value is the underlying CAS store config. | +| `ac` | array of [ActionCacheServiceConfig](#actioncacheserviceconfig) | — | — | The Action Cache (AC) backend config. The key is the `instance_name` used in the protocol and the value is the underlying AC store config. | +| `capabilities` | array of [CapabilitiesServiceConfig](#capabilitiesserviceconfig) | — | — | Capabilities service is required in order to use most of the bazel protocol. This service is used to provide the supported features and versions of this bazel gRPC service. | +| `execution` | array of [ExecutionServiceConfig](#executionserviceconfig) | — | — | The remote execution service configuration. NOTE: This service is under development and is currently just a place holder. | +| `bytestream` | array of [ByteStreamServiceConfig](#bytestreamserviceconfig) | — | — | This is the service used to stream data to and from the CAS. Bazel's protocol strongly encourages users to use this streaming interface to interact with the CAS when the data is large. | +| `fetch` | array of [FetchServiceConfig](#fetchserviceconfig) | — | — | These two are collectively the Remote Asset protocol, but it's defined as two separate services | +| `push` | array of [PushServiceConfig](#pushserviceconfig) | — | — | | +| `worker_api` | [WorkerApiConfig](#workerapiconfig) | — | — | This is the service used for workers to connect and communicate through. NOTE: This service should be served on a different, non-public port. In other words, `worker_api` configuration should not have any other services that are served on the same port. Doing so is a security risk, as workers have a different permission set than a client that makes the remote execution/cache requests. | +| `experimental_bep` | [BepConfig](#bepconfig) | — | — | Experimental - Build Event Protocol (BEP) configuration. This is the service that will consume build events from the client and publish them to a store for processing by an external service. | +| `admin` | [AdminConfig](#adminconfig) | — | — | This is the service for any administrative tasks. It provides a REST API endpoint for administrative purposes. | +| `health` | [HealthConfig](#healthconfig) | — | — | This is the service for health status check. | + +## IdentityHeaderSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `header_name` | string | — | "x-identity" | The name of the header to look for the identity in. | +| `required` | boolean | — | `false` | If the header is required to be set or fail the request. | + +## OriginEventsPublisherSpec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish nativelink events to. The store name referenced in the `stores` map in the main config. | + +## ConfigDigestHashFunction + +| Value | Description | +| --- | --- | +| `"sha256"` | Use the sha256 hash function. [https://en.wikipedia.org/wiki/SHA-2](https://en.wikipedia.org/wiki/SHA-2) | +| `"blake3"` | Use the blake3 hash function. [https://en.wikipedia.org/wiki/BLAKE_(hash_function)](https://en.wikipedia.org/wiki/BLAKE_(hash_function)) | + +## EvictionPolicy + +Eviction policy always works on LRU (Least Recently Used). Any time an entry +is touched it updates the timestamp. Inserts and updates will execute the +eviction policy removing any expired entries and/or the oldest entries +until the store size becomes smaller than `max_bytes`. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_bytes` | integer (uint) | — | 0 | Maximum number of bytes before eviction takes place. Zero means never evict based on size. | +| `evict_bytes` | integer (uint) | — | 0 | When eviction starts based on hitting `max_bytes`, continue until `max_bytes - evict_bytes` is met to create a low watermark. This stops operations from thrashing when the store is close to the limit. | +| `max_seconds` | integer (uint32) | — | 0 | Maximum number of seconds for an entry to live since it was last accessed before it is evicted. Zero means never evict based on time. | +| `max_count` | integer (uint64) | — | 0 | Maximum size of the store before an eviction takes place. Zero means never evict based on count. | + +## Retry + +Retry configuration. This configuration is exponential and each iteration +a jitter as a percentage is applied of the calculated delay. For example: +```haskell +Retry{ + max_retries: 7, + delay: 0.1, + jitter: 0.5, +} +``` +will result in: + +| Attempt | Delay | +| --- | --- | +| 1 | 0 ms | +| 2 | 75 to 125 ms | +| 3 | 150 to 250 ms | +| 4 | 300 to 500 ms | +| 5 | 600 ms to 1 s | +| 6 | 1.2 to 2 s | +| 7 | 2.4 to 4 s | +| 8 | 4.8 to 8 s | + +The total delay is additive, so this example produces 9.525 to 15.875 s of total delay for a single request. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_retries` | integer (uint) | — | `0` | Maximum number of retries until retrying stops. Setting this to zero will always attempt 1 time, but not retry. | +| `delay` | number (float) | — | `0` | Delay in seconds for exponential back off. | +| `jitter` | number (float) | — | `0` | Amount of jitter to add as a percentage in decimal form. This will change the formula like: | +| `retry_on_errors` | array of [ErrorCode](#errorcode) | — | — | A list of error codes to retry on, if this isn't set then the default error codes to retry on are used. These default codes are the most likely to be non-permanent: `Unknown`; `Cancelled`; `DeadlineExceeded`; `ResourceExhausted`; `Aborted`; `Internal`; `Unavailable`; `DataLoss` | + +## ExperimentalOntapS3Spec + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `endpoint` | string | Yes | — | | +| `vserver_name` | string | Yes | — | | +| `bucket` | string | Yes | — | | +| `root_certificates` | string | — | — | | +| `key_prefix` | string | — | — | If you wish to prefix the location in the bucket. If None, no prefix will be used. | +| `retry` | [Retry](#retry) | — | — | Retry configuration to use when a network request fails. | +| `consider_expired_after_s` | integer (uint32) | — | 0 | If the number of seconds since the `last_modified` time of the object is greater than this value, the object will not be considered "existing". This allows for external tools to delete objects that have not been uploaded in a long time. If a client receives a `NotFound` the client should re-upload the object. | +| `max_retry_buffer_per_request` | integer (uint) | — | 5MB | The maximum buffer size to retain in case of a retryable error during upload. Setting this to zero will disable upload buffering; this means that in the event of a failure during upload, the entire upload will be aborted and the client will likely receive an error. | +| `multipart_max_concurrent_uploads` | integer (uint) | — | 10 | Maximum number of concurrent `UploadPart` requests per `MultipartUpload`. | +| `insecure_allow_http` | boolean | — | false | Allow unencrypted HTTP connections. Only use this for local testing. | +| `disable_http2` | boolean | — | false | Disable HTTP/2 connections and only use HTTP/1.1. Default client configuration will have HTTP/1.1 and HTTP/2 enabled for connection schemes. HTTP/2 should be disabled if environments have poor support or performance related to HTTP/2. Safe to keep default unless underlying network environment, S3, or GCS API servers specify otherwise. | + +## CompressionAlgorithm + +Plus exactly one of the following variants (the key selects the variant): + +### `lz4` + +LZ4 compression algorithm is extremely fast for compression and +decompression, however does not perform very well in compression +ratio. In most cases build artifacts are highly compressible, however +lz4 is quite good at aborting early if the data is not deemed very +compressible. + +see: [https://lz4.github.io/lz4/](https://lz4.github.io/lz4/) + +**Type:** [Lz4Config](#lz4config) + +## StoreDirection + +| Value | Description | +| --- | --- | +| `"both"` | The store operates normally and all get and put operations are handled by it. | +| `"update"` | Update operations will cause persistence to this store, but Get operations will be ignored. This only makes sense on the fast store as the slow store will never get written to on Get anyway. | +| `"get"` | Get operations will cause persistence to this store, but Update operations will be ignored. | +| `"read_only"` | Operate as a read only store, only really makes sense if there's another way to write to it. | + +## ShardConfig + +Configuration for an individual shard of the store. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | [NamedStoreConfig](#namedstoreconfig) | Yes | — | Store to shard the data to. | +| `weight` | integer (uint32) | — | 1 | The weight of the store. This is used to determine how much data should be sent to the store. The actual percentage is the sum of all the store's weights divided by the individual store's weight. | + +## GrpcEndpoint + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `address` | string | Yes | — | The endpoint address (i.e. `grpc(s)://example.com:443`). | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint (if grpcs). | +| `concurrency_limit` | integer (uint) | — | — | The maximum concurrency to allow on this endpoint. | +| `connect_timeout_s` | integer (uint64) | — | 30 seconds | Timeout for establishing a TCP connection to the endpoint (seconds). | +| `tcp_keepalive_s` | integer (uint64) | — | 30 seconds | TCP keepalive interval (seconds). Sends TCP keepalive probes at this interval to detect dead connections at the OS level. | +| `http2_keepalive_interval_s` | integer (uint64) | — | 30 seconds | HTTP/2 keepalive interval (seconds). Sends HTTP/2 PING frames at this interval to detect dead connections at the application level. | +| `http2_keepalive_timeout_s` | integer (uint64) | — | 20 seconds | HTTP/2 keepalive timeout (seconds). If a PING response is not received within this duration, the connection is considered dead. | + +## StoreType + +| Value | Description | +| --- | --- | +| `"cas"` | The store is content addressable storage. | +| `"ac"` | The store is an action cache. | + +## GrpcReadBatchingConfig + +Configuration for experimental small-blob read coalescing in a gRPC +store. See [`GrpcSpec::experimental_read_batching`]. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_blob_size_bytes` | integer (uint64) | — | 131072 (128 KiB) | Only blobs at or below this size (in bytes) are eligible for batching. Larger blobs always use the `ByteStream` `Read` path. | +| `max_batch_bytes` | integer (uint64) | — | 3145728 (3 MiB) | Maximum total payload bytes packed into a single `BatchReadBlobs` request. This should leave headroom under the 4 MiB default gRPC message limit for protobuf framing overhead. | +| `dispatch_slots` | integer (uint) | — | 4 | Maximum number of concurrent `BatchReadBlobs` RPCs dispatched by the coalescer. Must be greater than zero. | +| `max_queued_bytes` | integer (uint64) | — | 33554432 (32 MiB) | Bound on the number of payload bytes waiting in the coalescer queue. When exceeded, new read requests bypass batching and fall back to the regular `ByteStream` `Read` path instead of blocking. | + +## RedisMode + +| Value | Description | +| --- | --- | +| `"cluster"` | Use Redis Cluster. | +| `"sentinel"` | Use Redis Sentinel. | +| `"standard"` | Use a standalone Redis server. | + +## EndpointConfig + +Generic config for an endpoint and associated configs. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `uri` | string | Yes | — | URI of the endpoint. | +| `timeout` | number (float) | — | 5 seconds | Timeout in seconds that a request should take. | +| `tls_config` | [ClientTlsConfig](#clienttlsconfig) | — | — | The TLS configuration to use to connect to the endpoint. | + +## UploadActionResultConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ac_store` | string | — | {No uploading is done} | Underlying AC store that the worker will use to publish execution results into. Objects placed in this store should be reachable from the scheduler/client-cas after they have finished updating. | +| `upload_ac_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `SuccessOnly` | In which situations should the results be published to the `ac_store`, if set to `SuccessOnly` then only results with an exit code of 0 will be uploaded, if set to Everything all completed results will be uploaded. | +| `historical_results_store` | string | — | {CAS store of parent} | Store to upload historical results to. This should be a CAS store if set. | +| `upload_historical_results_strategy` | [UploadCacheResultsStrategy](#uploadcacheresultsstrategy) | — | `FailuresOnly` | In which situations should the results be published to the historical CAS. The historical CAS is where failures are published. These messages conform to the CAS key-value lookup format and are always a `HistoricalExecuteResponse` serialized message. | +| `success_message_template` | string | — | "" (no message) | Template to use for the `ExecuteResponse.message` property. This message is attached to the response before it is sent to the client. The following special variables are supported:; `digest_function`: Digest function used to calculate the action digest: `action_digest_hash`: Action digest hash: `action_digest_size`: Action digest size: `historical_results_hash`: `HistoricalExecuteResponse` digest hash: `historical_results_size`: `HistoricalExecuteResponse` digest size. | +| `failure_message_template` | string | — | "" (no message) | Same as `success_message_template` but for failure case. | + +## WorkerProperty + +Plus exactly one of the following variants (the key selects the variant): + +### `values` + +List of static values. +Note: Generally there should only ever be 1 value, but if the platform +property key is `PropertyType::Priority` it may have more than one value. + +**Type:** array of string + +### `query_cmd` + +A dynamic configuration. The string will be executed as a command +(not shell) and will be split by "\n" (new line character). + +**Type:** string + +## EnvironmentSource + +One of: + +- `property`: string — The name of the platform property in the action to get the value from. +- `value`: string — The raw value to set. +- `"from_environment"` — Take the value from the local environment corresponding to the name key +- `"timeout_millis"` — The max amount of time in milliseconds the command is allowed to run (requested by the client). +- `"side_channel_file"` — A special file path will be provided that can be used to communicate with the parent process about out-of-band information. This file will be read after the command has finished executing. Based on the contents of the file, the behavior of the result may be modified. +- `"action_directory"` — A "root" directory for the action. This directory can be used to store temporary files that are not needed after the action has completed. This directory will be purged after the action has completed. + +## DirectoryCacheConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `max_entries` | integer (uint) | — | 1000 | Maximum number of cached directories. | +| `max_size_bytes` | integer (uint64) | — | 10737418240 (10 GB) | Maximum total size in bytes for all cached directories (0 = unlimited). | +| `cache_root` | string | — | `{work_directory}/../directory_cache` | Base directory for cache storage. This directory will be managed by the worker and should be on the same filesystem as `work_directory`. | +| `experimental_subtree_caching` | boolean | — | false (only root directories are cached; existing behavior) | Optional and experimental: additionally cache every subdirectory by its own `Directory` digest, not just the root directory. REAPI Merkle nodes are content-addressed, so a subtree that is byte-identical between two different roots has the same digest and can be materialized with a single hardlink pass instead of being rebuilt from the CAS. This makes the common "one input file changed out of thousands" case reuse every unchanged subtree. | +| `max_concurrent_fetches` | integer (uint) | — | 64 | Maximum number of concurrent slow-store fetches across ALL directory constructions of this cache. This bound protects backing stores from RPC storms: per-level construction concurrency compounds multiplicatively across tree levels and concurrent actions. | +| `experimental_get_tree_prefetch` | boolean | — | false | On a directory-cache miss, prefetch every `Directory` proto of the tree with one logical `GetTree` traversal instead of fetching protos level by level (which costs one round trip per tree DEPTH). The [REAPI request contract] permits servers to impose their own limit even when no page size is specified, and the [REAPI response contract] requires clients to continue with the returned page token. A paginated traversal may therefore use multiple RPCs. Only takes effect when the slow tier is a `grpc` store; any prefetch failure falls back to the per-level path. Worthwhile when worker-to-CAS latency is non-trivial and trees are deep; measured 5-34x on the proto phase at 5-25ms RTT. Note the serving CAS pays the tree walk against its own backend, so its directory protos should be served from a fast tier. | + +## PropertyType + +When the scheduler matches tasks to workers that are capable of running +the task, this value will be used to determine how the property is treated. + +One of: + +- string +- `"minimum"` — Requires the platform property to be a u64 and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that has less than this value. +- `"exact"` — Requires the platform property to be a string and when the scheduler looks for appropriate worker nodes that are capable of executing the task, the task will not run on a node that does not have this property set to the value with exact string match. +- `"priority"` — Does not restrict on this value and instead will be passed to the worker as an informational piece. In the future this will be used by the scheduler and worker to cause the scheduler to prefer certain workers over others, but not restrict them based on these values. + +## WorkerAllocationStrategy + +When a worker is being searched for to run a job, this will be used +on how to choose which worker should run the job when multiple +workers are able to run the task. + +| Value | Description | +| --- | --- | +| `"least_recently_used"` | Prefer workers that have been least recently used to run a job. | +| `"most_recently_used"` | Prefer workers that have been most recently used to run a job. | + +## ExperimentalSimpleSchedulerBackend + +One of: + +- `"memory"` — Use an in-memory store for the scheduler. +- `redis`: [ExperimentalRedisSchedulerBackend](#experimentalredisschedulerbackend) — Use a Redis store for the scheduler. + +## SchedulerSpec + +Plus exactly one of the following variants (the key selects the variant): + +### `simple` + +**Type:** [SimpleSpec](#simplespec) + +### `grpc` + +**Type:** [SchedulerGrpcSpec](#schedulergrpcspec) + +### `cache_lookup` + +**Type:** [CacheLookupSpec](#cachelookupspec) + +### `property_modifier` + +**Type:** [PropertyModifierSpec](#propertymodifierspec) + +### `historical_resource` + +**Type:** [HistoricalResourceSpec](#historicalresourcespec) + +## PropertyModification + +Plus exactly one of the following variants (the key selects the variant): + +### `add` + +Add a property to the action properties. + +**Type:** [PlatformPropertyAddition](#platformpropertyaddition) + +### `remove` + +Remove a named property from the action. + +**Type:** string + +### `replace` + +If a property is found, then replace it with another one. + +**Type:** [PlatformPropertyReplacement](#platformpropertyreplacement) + +## HttpListener + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `socket_address` | string | Yes | — | Address to listen on. Example: `127.0.0.1:8080` or `:8080` to listen to all IPs. | +| `freebind` | boolean | — | false | Allow binding `socket_address` before it is assigned locally. | +| `compression` | [HttpCompressionConfig](#httpcompressionconfig) | — | — | Data transport compression configuration to use for this service. | +| `advanced_http` | [HttpServerConfig](#httpserverconfig) | — | — | Advanced HTTP server configuration. | +| `max_decoding_message_size` | integer (uint) | — | 4 MiB | Maximum number of bytes to decode on each grpc stream chunk. | +| `tls` | [TlsConfig](#tlsconfig) | — | — | TLS configuration for this server. If not set, the server will not use TLS. | + +## CasServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `experimental_chunking` | [CasChunkingConfig](#caschunkingconfig) | — | not set — chunking RPCs are rejected, nothing is advertised, | Optional and experimental: enables the REAPI `SplitBlob`/`SpliceBlob` RPCs used by content-defined chunking clients (e.g. Bazel's `--experimental_remote_cache_chunking`). When set, the capabilities service advertises blob split/splice support and `FastCDC` 2020 parameters for this instance. When `cas_store` is a grpc store the RPCs are forwarded to the backend (which must support chunking with matching parameters); otherwise they are served locally. | + +## ActionCacheServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `ac_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## CapabilitiesServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `remote_execution` | [CapabilitiesRemoteExecutionConfig](#capabilitiesremoteexecutionconfig) | — | — | Configuration for remote execution capabilities. If not set the capabilities service will inform the client that remote execution is not supported. | +| `remote_cache_compression` | boolean | — | — | Whether this instance supports Bazel remote cache compression. When enabled, the capabilities service advertises zstd wire compression and the ByteStream/CAS services accept REAPI compressed-blobs/zstd data. | + +## ExecutionServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. This value must be a CAS store reference. | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## ByteStreamServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `cas_store` | string | Yes | — | Name of the store in the "stores" configuration. | +| `max_bytes_per_stream` | integer (uint) | — | 64KiB | Max number of bytes to send on each grpc stream chunk. According to [https://github.com/grpc/grpc.github.io/issues/371](https://github.com/grpc/grpc.github.io/issues/371) 16KiB - 64KiB is optimal. | +| `persist_stream_on_disconnect_timeout_s` | integer (uint) | — | 10 seconds | In the event a client disconnects while uploading a blob, we will hold the internal stream open for this many seconds before closing it. This allows clients that disconnect to reconnect and continue uploading the same blob. | + +## FetchServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `fetch_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | + +## PushServiceConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `instance_name` | string | — | `""` | Used when the config references `instance_name` in the protocol. | +| `push_store` | string | Yes | — | The store name referenced in the `stores` map in the main config. This store name referenced here may be reused multiple times. | +| `read_only` | boolean | — | `false` | Whether the Action Cache store may be written to, this if set to false it is only possible to read from the Action Cache. | + +## WorkerApiConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | The scheduler name referenced in the `schedulers` map in the main config. | + +## BepConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `store` | string | Yes | — | The store to publish build events to. The store name referenced in the `stores` map in the main config. | + +## AdminConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/admin" | Path to register the admin API. If path is "/admin", and your domain is "example.com", you can reach the endpoint with: [http://example.com/admin](http://example.com/admin). | + +## HealthConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `path` | string | — | "/status" | Path to register the health status check. If path is "/status", and your domain is "example.com", you can reach the endpoint with: [http://example.com/status](http://example.com/status). | +| `timeout_seconds` | integer (uint64) | — | 5s | Timeout on health checks. | + +## ErrorCode + +The possible error codes that might occur on an upstream request. + +| Value | Description | +| --- | --- | +| `"Cancelled"` | | +| `"Unknown"` | | +| `"InvalidArgument"` | | +| `"DeadlineExceeded"` | | +| `"NotFound"` | | +| `"AlreadyExists"` | | +| `"PermissionDenied"` | | +| `"ResourceExhausted"` | | +| `"FailedPrecondition"` | | +| `"Aborted"` | | +| `"OutOfRange"` | | +| `"Unimplemented"` | | +| `"Internal"` | | +| `"Unavailable"` | | +| `"DataLoss"` | | +| `"Unauthenticated"` | | + +## Lz4Config + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `block_size` | integer (uint32) | — | 65536 (64k) | Size of the blocks to compress. Higher values require more ram, but might yield slightly better compression ratios. | +| `max_decode_block_size` | integer (uint32) | — | value in `block_size` | Maximum size allowed to attempt to deserialize data into. This is needed because the `block_size` is embedded into the data so if there was a bad actor, they could upload an extremely large `block_size`'ed entry and we'd allocate a large amount of memory when retrieving the data. To prevent this from happening, we allow you to specify the maximum that we'll attempt to deserialize. | + +## ClientTlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `ca_file` | string | — | — | Path to the certificate authority to use to validate the remote. | +| `cert_file` | string | — | — | Path to the certificate file for client authentication. | +| `key_file` | string | — | — | Path to the private key file for client authentication. | +| `use_native_roots` | boolean | — | false | If set the client will use the native roots for TLS connections. | + +## UploadCacheResultsStrategy + +| Value | Description | +| --- | --- | +| `"success_only"` | Only upload action results with an exit code of 0. | +| `"never"` | Don't upload any action results. | +| `"everything"` | Upload all action results that complete. | +| `"failures_only"` | Only upload action results that fail. | + +## ExperimentalRedisSchedulerBackend + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `redis_store` | string | Yes | — | A reference to the Redis store to use for the scheduler. Note: This MUST resolve to a `RedisSpec`. | + +## PlatformPropertyAddition + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to add. | +| `value` | string | Yes | — | The value to assign to the property. | + +## PlatformPropertyReplacement + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `name` | string | Yes | — | The name of the property to replace. | +| `value` | string | — | — | The value to match against, if unset then any instance matches. | +| `new_name` | string | Yes | — | The new name of the property. | +| `new_value` | string | — | — | The value to assign to the property, if unset will remain the same. | + +## HttpCompressionConfig + +Note: Compressing data in the cloud rarely has a benefit, since most +cloud providers have very high bandwidth backplanes. However, for +clients not inside the data center, it might be a good idea to +compress data to and from the cloud. This will however come at a high +CPU and performance cost. If you are making remote execution share the +same CAS/AC servers as client's remote cache, you can create multiple +services with different compression settings that are served on +different ports. Then configure the non-cloud clients to use one port +and cloud-clients to use another. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `send_compression_algorithm` | [HttpCompressionAlgorithm](#httpcompressionalgorithm) | — | `HttpCompressionAlgorithm::None` | The compression algorithm that the server will use when sending responses to clients. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | +| `accepted_compression_algorithms` | array of [HttpCompressionAlgorithm](#httpcompressionalgorithm) | Yes | {no supported compression} | The compression algorithm that the server will accept from clients. The server will broadcast the supported compression algorithms to clients and the client will choose which compression algorithm to use. Enabling this will likely save a lot of data transfer, but will consume a lot of CPU and add a lot of latency. see: [https://github.com/tracemachina/nativelink/issues/109](https://github.com/tracemachina/nativelink/issues/109) | + +## HttpServerConfig + +Advanced HTTP configuration. These generally should not be set. +For documentation on these settings, see the hyper documentation: +See: [hyper HTTP server docs](https://docs.rs/hyper/latest/hyper/server/conn/struct.Http.html) + +Note: All of these default to the default values from hyper unless otherwise +specified. + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `http2_keep_alive_interval` | integer (uint32) | — | — | Interval to send keep-alive pings via HTTP2. Note: This is in seconds. | +| `experimental_http2_max_pending_accept_reset_streams` | integer (uint32) | — | — | | +| `experimental_http2_initial_stream_window_size` | integer (uint32) | — | — | | +| `experimental_http2_initial_connection_window_size` | integer (uint32) | — | — | | +| `experimental_http2_adaptive_window` | boolean | — | — | | +| `experimental_http2_max_frame_size` | integer (uint32) | — | — | | +| `experimental_http2_max_concurrent_streams` | integer (uint32) | — | — | | +| `experimental_http2_keep_alive_timeout_s` | integer (uint32) | — | — | | +| `experimental_http2_max_send_buf_size` | integer (uint32) | — | — | | +| `experimental_http2_enable_connect_protocol` | boolean | — | — | | +| `experimental_http2_max_header_list_size` | integer (uint32) | — | — | | + +## TlsConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `cert_file` | string | Yes | — | Path to the certificate file. | +| `key_file` | string | Yes | — | Path to the private key file. | +| `client_ca_file` | string | — | — | Path to the certificate authority for mTLS, if client authentication is required for this endpoint. | +| `client_crl_file` | string | — | — | Path to the certificate revocation list for mTLS, if client authentication is required for this endpoint. | + +## CasChunkingConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `index_store` | string | — | — | The store name referenced in the `stores` map in the main config used to persist blob-to-chunks layouts. Keys are the digests of the original blobs and values are serialized chunk layouts (which do not hash to those digests), so this store MUST NOT perform content digest verification and MUST NOT be the same store as `cas_store` — writing layouts into the CAS would overwrite blob content. Using the same store name as `cas_store` is rejected at startup. | +| `avg_chunk_size_bytes` | integer (uint64) | — | 524288 (512 KiB) | The average chunk size in bytes advertised to clients through the `FastCDC` 2020 capability parameters and used for server-side chunking in `SplitBlob`. Clients derive the minimum and maximum chunk sizes from this value (avg / 4 and avg * 4). The value must be between 1 KiB and 1 MiB. | +| `max_chunk_count` | integer (uint64) | — | 50000 | Maximum number of chunks accepted in a `SpliceBlob` request or produced by on-demand chunking in `SplitBlob`. Blobs that would produce more chunks are served without chunking (`SplitBlob` returns `NOT_FOUND` and clients fall back to a regular download). This bounds the size of stored chunk layouts and of `SplitBlobResponse` messages (roughly 80-140 bytes per chunk). At the default average chunk size the default cap supports blobs up to ~25 GiB; note that values above ~50000 may produce responses that exceed default gRPC message size limits on clients. | + +## CapabilitiesRemoteExecutionConfig + +| Field | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `scheduler` | string | Yes | — | Scheduler used to configure the capabilities of remote execution. | + +## HttpCompressionAlgorithm + +| Value | Description | +| --- | --- | +| `"none"` | No compression. | +| `"gzip"` | Zlib compression. | + +## Reading the source + +If anything here disagrees with the binary, the source wins: + +- [`stores.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.3/nativelink-config/src/stores.rs) +- [`cas_server.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.3/nativelink-config/src/cas_server.rs) +- [`schedulers.rs`](https://github.com/TraceMachina/nativelink/tree/v1.6.3/nativelink-config/src/schedulers.rs) diff --git a/web/apps/docs/lib/config-versions.ts b/web/apps/docs/lib/config-versions.ts index 624a044b4..22c50f1a5 100644 --- a/web/apps/docs/lib/config-versions.ts +++ b/web/apps/docs/lib/config-versions.ts @@ -28,13 +28,53 @@ export const CONFIG_VERSIONS: ConfigVersion[] = [ "isDev": true }, { - "version": "v1.5.2", - "label": "v1.5.2 (latest)", + "version": "v1.6.4", + "label": "v1.6.4 (latest)", "href": "/reference/nativelink-config", - "ref": "v1.5.2", + "ref": "v1.6.4", "isLatest": true, "isDev": false }, + { + "version": "v1.6.3", + "label": "v1.6.3", + "href": "/reference/nativelink-config/v1.6.3", + "ref": "v1.6.3", + "isLatest": false, + "isDev": false + }, + { + "version": "v1.6.2", + "label": "v1.6.2", + "href": "/reference/nativelink-config/v1.6.2", + "ref": "v1.6.2", + "isLatest": false, + "isDev": false + }, + { + "version": "v1.6.1", + "label": "v1.6.1", + "href": "/reference/nativelink-config/v1.6.1", + "ref": "v1.6.1", + "isLatest": false, + "isDev": false + }, + { + "version": "v1.6.0", + "label": "v1.6.0", + "href": "/reference/nativelink-config/v1.6.0", + "ref": "v1.6.0", + "isLatest": false, + "isDev": false + }, + { + "version": "v1.5.2", + "label": "v1.5.2", + "href": "/reference/nativelink-config/v1.5.2", + "ref": "v1.5.2", + "isLatest": false, + "isDev": false + }, { "version": "v1.5.1", "label": "v1.5.1", @@ -99,14 +139,6 @@ export const CONFIG_VERSIONS: ConfigVersion[] = [ "isLatest": false, "isDev": false }, - { - "version": "v1.0.1", - "label": "v1.0.1", - "href": "/reference/nativelink-config/v1.0.1", - "ref": "v1.0.1", - "isLatest": false, - "isDev": false - }, { "version": "v1.0.0", "label": "v1.0.0", diff --git a/web/apps/docs/mdx-components.tsx b/web/apps/docs/mdx-components.tsx index 39873cc62..1c48b6e67 100644 --- a/web/apps/docs/mdx-components.tsx +++ b/web/apps/docs/mdx-components.tsx @@ -2,6 +2,7 @@ import { Callout } from "@/components/callout"; import { ConfigVersionSwitcher } from "@/components/config-version-switcher"; import { Mermaid } from "@/components/mermaid"; import { Steps } from "@/components/steps"; +import { Accordion, Accordions } from "fumadocs-ui/components/accordion"; import { Callout as FumadocsCallout } from "fumadocs-ui/components/callout"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; import defaultMdxComponents from "fumadocs-ui/mdx"; @@ -20,6 +21,8 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents { Tabs, Tab, Mermaid, + Accordions, + Accordion, ...components, }; } diff --git a/web/apps/docs/next.config.mjs b/web/apps/docs/next.config.mjs index 9b89fe643..27918d7c2 100644 --- a/web/apps/docs/next.config.mjs +++ b/web/apps/docs/next.config.mjs @@ -15,6 +15,35 @@ const nextConfig = { destination: "/configuration/production", permanent: true, }, + { + source: "/getting-started/other-build-systems/reclient", + destination: "/getting-started/other-build-systems/siso", + permanent: true, + }, + // The standalone /faq section was dissolved into per-page FAQ + // sections; keep its published URLs resolving to the new homes. + ...Object.entries({ + architecture: "/explanations/architecture#faq", + caching: "/getting-started/setup#faq", + clients: "/getting-started/other-build-systems#faq", + configuration: "/configuration/intro#faq", + contributing: "/contribute/guidelines#faq", + cost: "/getting-started/on-prem#faq", + deployment: "/deployment/on-prem-overview#faq", + hermeticity: "/explanations/lre#faq", + lre: "/explanations/lre#faq", + nix: "/contribute/nix#faq", + observability: "/deployment/metrics#faq", + "remote-execution": "/rbe/examples#faq", + rust: "/explanations/history#faq", + stores: "/reference/nativelink-config/store-overview#faq", + toolchains: "/rbe/examples#faq", + troubleshooting: "/getting-started/setup#faq", + }).map(([slug, destination]) => ({ + source: `/faq/${slug}`, + destination, + permanent: true, + })), ]; }, }; diff --git a/web/apps/docs/package.json b/web/apps/docs/package.json index d61a9b2bd..a0e19f38c 100644 --- a/web/apps/docs/package.json +++ b/web/apps/docs/package.json @@ -4,6 +4,7 @@ "dependencies": { "@nativelink/tokens": "workspace:*", "@nativelink/ui": "workspace:*", + "@next/third-parties": "^16.2.11", "fumadocs-core": "^16", "fumadocs-mdx": "^15", "fumadocs-ui": "^16", @@ -25,9 +26,10 @@ }, "private": true, "scripts": { - "build": "next build", + "build": "node scripts/gen-changelog.mjs && next build", "clean": "rm -rf .next .turbo .source", - "dev": "next dev --port 3001", + "dev": "node scripts/gen-changelog.mjs && next dev --port 3001", + "gen:changelog": "node scripts/gen-changelog.mjs", "gen:config-reference": "node scripts/gen-config-reference.mjs", "lint": "biome check .", "start": "next start --port 3001", diff --git a/web/apps/docs/scripts/gen-changelog.mjs b/web/apps/docs/scripts/gen-changelog.mjs new file mode 100644 index 000000000..ee373e68b --- /dev/null +++ b/web/apps/docs/scripts/gen-changelog.mjs @@ -0,0 +1,183 @@ +#!/usr/bin/env node +// Generate the changelog reference page from the repository's canonical +// CHANGELOG.md (maintained with git-cliff at release time; see /cliff.toml and +// the "Creating a Release" section of CONTRIBUTING.md). +// +// The output at content/docs/reference/changelog.md is gitignored and +// regenerated as part of the `dev` and `build` scripts, so the published page +// always mirrors the CHANGELOG.md of the commit being deployed: every merge to +// main produces a fresh page via the production build, and the web CI build on +// pull requests fails if a changelog edit stops compiling. +// +// The page is emitted as plain markdown (.md), which fumadocs compiles +// without JSX or ESM support: `{`, `}`, and statement-like lines such as +// `import x from "y"` in commit subjects are inert text there, while in .mdx +// each of them is syntax that can break the compile. The transform: +// 1. drop the static git-cliff header (everything before the first `## `), +// replacing it with frontmatter and a short intro, +// 2. drop git-cliff's whole-line comment marker lines by exact string +// comparison against the known markers (step 3 would otherwise escape +// them into visible text), +// 3. backslash-escape `\` and `<` outside inline code spans and fenced +// code blocks, so commit subjects can't smuggle raw HTML like +// `